Home | History | Annotate | Line # | Download | only in ic
com.c revision 1.6
      1 /*-
      2  * Copyright (c) 1991 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  *	@(#)com.c	7.5 (Berkeley) 5/16/91
     34  *
     35  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
     36  * --------------------         -----   ----------------------
     37  * CURRENT PATCH LEVEL:         4       00079
     38  * --------------------         -----   ----------------------
     39  *
     40  * 23 Sep 92	Rodney W. Grimes	Fix SILO overflow on 16550 UARTS
     41  * 30 Aug 92	Poul-Henning Kamp	Stabilize SLIP on lossy lines/UARTS
     42  * 09 Aug 92	Christoph Robitschko	Correct minor number on com ports
     43  * 10 Feb 93	Jordan K. Hubbard	Added select code
     44  */
     45 static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/sys/dev/ic/com.c,v 1.6 1993/04/10 12:05:19 glass Exp $";
     46 
     47 #include "com.h"
     48 #if NCOM > 0
     49 /*
     50  * COM driver, based on HP dca driver
     51  * uses National Semiconductor NS16450/NS16550AF UART
     52  */
     53 #include "param.h"
     54 #include "systm.h"
     55 #include "ioctl.h"
     56 #include "tty.h"
     57 #include "proc.h"
     58 #include "user.h"
     59 #include "conf.h"
     60 #include "file.h"
     61 #include "uio.h"
     62 #include "kernel.h"
     63 #include "syslog.h"
     64 #include "types.h"
     65 
     66 #include "i386/isa/isa_device.h"
     67 #include "i386/isa/comreg.h"
     68 #include "i386/isa/ic/ns16550.h"
     69 #define cominor(d)
     70 
     71 int 	comprobe(), comattach(), comintr(), comstart(), comparam();
     72 
     73 struct	isa_driver comdriver = {
     74 	comprobe, comattach, "com"
     75 };
     76 
     77 int	comsoftCAR;
     78 int	com_active;
     79 int	com_hasfifo;
     80 int	ncom = NCOM;
     81 #ifdef COMCONSOLE
     82 int	comconsole = COMCONSOLE;
     83 #else
     84 int	comconsole = -1;
     85 #endif
     86 int	comconsinit;
     87 int	comdefaultrate = TTYDEF_SPEED;
     88 int	commajor;
     89 short com_addr[NCOM];
     90 struct	tty com_tty[NCOM];
     91 
     92 struct speedtab comspeedtab[] = {
     93 	0,	0,
     94 	50,	COMBRD(50),
     95 	75,	COMBRD(75),
     96 	110,	COMBRD(110),
     97 	134,	COMBRD(134),
     98 	150,	COMBRD(150),
     99 	200,	COMBRD(200),
    100 	300,	COMBRD(300),
    101 	600,	COMBRD(600),
    102 	1200,	COMBRD(1200),
    103 	1800,	COMBRD(1800),
    104 	2400,	COMBRD(2400),
    105 	4800,	COMBRD(4800),
    106 	9600,	COMBRD(9600),
    107 	19200,	COMBRD(19200),
    108 	38400,	COMBRD(38400),
    109 	57600,	COMBRD(57600),
    110 	-1,	-1
    111 };
    112 
    113 extern	struct tty *constty;
    114 #ifdef KGDB
    115 #include "machine/remote-sl.h"
    116 
    117 extern int kgdb_dev;
    118 extern int kgdb_rate;
    119 extern int kgdb_debug_init;
    120 #endif
    121 
    122 #define	UNIT(x)		(minor(x))
    123 
    124 comprobe(dev)
    125 struct isa_device *dev;
    126 {
    127 	/* force access to id reg */
    128 	outb(dev->id_iobase+com_cfcr, 0);
    129 	outb(dev->id_iobase+com_iir, 0);
    130 	DELAY(100);
    131 	if ((inb(dev->id_iobase+com_iir) & 0x38) == 0)
    132 		return(8);
    133 	return(0);
    134 }
    135 
    136 
    137 int
    138 comattach(isdp)
    139 struct isa_device *isdp;
    140 {
    141 	struct	tty	*tp;
    142 	u_char		unit;
    143 	int		port = isdp->id_iobase;
    144 
    145 	unit = isdp->id_unit;
    146 	if (unit == comconsole)
    147 		DELAY(1000);
    148 	com_addr[unit] = port;
    149 	com_active |= 1 << unit;
    150 	comsoftCAR |= 1 << unit;	/* XXX */
    151 
    152 	/* look for a NS 16550AF UART with FIFOs */
    153 	outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
    154 	DELAY(100);
    155 	if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) {
    156 		com_hasfifo |= 1 << unit;
    157 		printf("com%d: fifo\n", isdp->id_unit);
    158 	}
    159 
    160 	outb(port+com_ier, 0);
    161 	outb(port+com_mcr, 0 | MCR_IENABLE);
    162 #ifdef KGDB
    163 	if (kgdb_dev == makedev(commajor, unit)) {
    164 		if (comconsole == unit)
    165 			kgdb_dev = -1;	/* can't debug over console port */
    166 		else {
    167 			(void) cominit(unit, kgdb_rate);
    168 			if (kgdb_debug_init) {
    169 				/*
    170 				 * Print prefix of device name,
    171 				 * let kgdb_connect print the rest.
    172 				 */
    173 				printf("com%d: ", unit);
    174 				kgdb_connect(1);
    175 			} else
    176 				printf("com%d: kgdb enabled\n", unit);
    177 		}
    178 	}
    179 #endif
    180 	/*
    181 	 * Need to reset baud rate, etc. of next print so reset comconsinit.
    182 	 * Also make sure console is always "hardwired"
    183 	 */
    184 	if (unit == comconsole) {
    185 		comconsinit = 0;
    186 		comsoftCAR |= (1 << unit);
    187 	}
    188 	return (1);
    189 }
    190 
    191 /* ARGSUSED */
    192 comopen(dev_t dev, int flag, int mode, struct proc *p)
    193 {
    194 	register struct tty *tp;
    195 	register int unit;
    196 	int error = 0;
    197 
    198 	unit = UNIT(dev);
    199 	if (unit >= NCOM || (com_active & (1 << unit)) == 0)
    200 		return (ENXIO);
    201 	tp = &com_tty[unit];
    202 	tp->t_oproc = comstart;
    203 	tp->t_param = comparam;
    204 	tp->t_dev = dev;
    205 	if ((tp->t_state & TS_ISOPEN) == 0) {
    206 		tp->t_state |= TS_WOPEN;
    207 		ttychars(tp);
    208 		if (tp->t_ispeed == 0) {
    209 			tp->t_iflag = TTYDEF_IFLAG;
    210 			tp->t_oflag = TTYDEF_OFLAG;
    211 			tp->t_cflag = TTYDEF_CFLAG;
    212 			tp->t_lflag = TTYDEF_LFLAG;
    213 			tp->t_ispeed = tp->t_ospeed = comdefaultrate;
    214 		}
    215 		comparam(tp, &tp->t_termios);
    216 		ttsetwater(tp);
    217 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
    218 		return (EBUSY);
    219 	(void) spltty();
    220 	(void) commctl(dev, MCR_DTR | MCR_RTS, DMSET);
    221 	if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD))
    222 		tp->t_state |= TS_CARR_ON;
    223 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
    224 	       (tp->t_state & TS_CARR_ON) == 0) {
    225 		tp->t_state |= TS_WOPEN;
    226 		if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
    227 		    ttopen, 0))
    228 			break;
    229 	}
    230 	(void) spl0();
    231 	if (error == 0)
    232 		error = (*linesw[tp->t_line].l_open)(dev, tp);
    233 	return (error);
    234 }
    235 
    236 /*ARGSUSED*/
    237 comclose(dev, flag, mode, p)
    238 	dev_t dev;
    239 	int flag, mode;
    240 	struct proc *p;
    241 {
    242 	register struct tty *tp;
    243 	register com;
    244 	register int unit;
    245 
    246 	unit = UNIT(dev);
    247 	com = com_addr[unit];
    248 	tp = &com_tty[unit];
    249 	(*linesw[tp->t_line].l_close)(tp, flag);
    250 	outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
    251 #ifdef KGDB
    252 	/* do not disable interrupts if debugging */
    253 	if (kgdb_dev != makedev(commajor, unit))
    254 #endif
    255 	outb(com+com_ier, 0);
    256 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
    257 	    (tp->t_state&TS_ISOPEN) == 0)
    258 		(void) commctl(dev, 0, DMSET);
    259 	ttyclose(tp);
    260 	return(0);
    261 }
    262 
    263 comread(dev, uio, flag)
    264 	dev_t dev;
    265 	struct uio *uio;
    266 {
    267 	register struct tty *tp = &com_tty[UNIT(dev)];
    268 
    269 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
    270 }
    271 
    272 comwrite(dev, uio, flag)
    273 	dev_t dev;
    274 	struct uio *uio;
    275 {
    276 	int unit = UNIT(dev);
    277 	register struct tty *tp = &com_tty[unit];
    278 
    279 	/*
    280 	 * (XXX) We disallow virtual consoles if the physical console is
    281 	 * a serial port.  This is in case there is a display attached that
    282 	 * is not the console.  In that situation we don't need/want the X
    283 	 * server taking over the console.
    284 	 */
    285 	if (constty && unit == comconsole)
    286 		constty = NULL;
    287 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    288 }
    289 
    290 comintr(unit)
    291 	register int unit;
    292 {
    293 	register com;
    294 	register u_char code;
    295 	register struct tty *tp;
    296 
    297 	unit;
    298 	com = com_addr[unit];
    299 	while (1) {
    300 		code = inb(com+com_iir);
    301 		switch (code & IIR_IMASK) {
    302 		case IIR_NOPEND:
    303 			return (1);
    304 		case IIR_RXTOUT:
    305 		case IIR_RXRDY:
    306 			tp = &com_tty[unit];
    307 /*
    308  * Process received bytes.  Inline for speed...
    309  */
    310 #ifdef KGDB
    311 #define	RCVBYTE() \
    312 			code = inb(com+com_data); \
    313 			if ((tp->t_state & TS_ISOPEN) == 0) { \
    314 				if (kgdb_dev == makedev(commajor, unit) && \
    315 				    code == FRAME_END) \
    316 					kgdb_connect(0); /* trap into kgdb */ \
    317 			} else \
    318 				(*linesw[tp->t_line].l_rint)(code, tp)
    319 #else
    320 #define	RCVBYTE() \
    321 			code = inb(com+com_data); \
    322 			if (tp->t_state & TS_ISOPEN) \
    323 				(*linesw[tp->t_line].l_rint)(code, tp)
    324 #endif
    325 
    326 			RCVBYTE();
    327 
    328 			if (com_hasfifo & (1 << unit))
    329 				while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
    330 					if (code == LSR_RXRDY) {
    331 						RCVBYTE();
    332 					} else
    333 						comeint(unit, code, com);
    334 				}
    335 			break;
    336 		case IIR_TXRDY:
    337 			tp = &com_tty[unit];
    338 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
    339 			if (tp->t_line)
    340 				(*linesw[tp->t_line].l_start)(tp);
    341 			else
    342 				comstart(tp);
    343 			break;
    344 		case IIR_RLS:
    345 			comeint(unit, inb(com+com_lsr), com);
    346 			break;
    347 		default:
    348 			if (code & IIR_NOPEND)
    349 				return (1);
    350 			log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
    351 			    unit, code);
    352 			/* fall through */
    353 		case IIR_MLSC:
    354 			commint(unit, com);
    355 			break;
    356 		}
    357 	}
    358 }
    359 
    360 comeint(unit, stat, com)
    361 	register int unit, stat;
    362 	register com;
    363 {
    364 	register struct tty *tp;
    365 	register int c;
    366 
    367 	tp = &com_tty[unit];
    368 	c = inb(com+com_data);
    369 	if ((tp->t_state & TS_ISOPEN) == 0) {
    370 #ifdef KGDB
    371 		/* we don't care about parity errors */
    372 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
    373 		    kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
    374 			kgdb_connect(0); /* trap into kgdb */
    375 #endif
    376 		return;
    377 	}
    378 	if (stat & (LSR_BI | LSR_FE))
    379 		c |= TTY_FE;
    380 	else if (stat & LSR_PE)
    381 		c |= TTY_PE;
    382 	else if (stat & LSR_OE) {			/* 30 Aug 92*/
    383 		c |= TTY_PE;	/* Ought to have it's own define... */
    384 		log(LOG_WARNING, "com%d: silo overflow\n", unit);
    385 	}
    386 	(*linesw[tp->t_line].l_rint)(c, tp);
    387 }
    388 
    389 commint(unit, com)
    390 	register int unit;
    391 	register com;
    392 {
    393 	register struct tty *tp;
    394 	register int stat;
    395 
    396 	tp = &com_tty[unit];
    397 	stat = inb(com+com_msr);
    398 	if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
    399 		if (stat & MSR_DCD)
    400 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
    401 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
    402 			outb(com+com_mcr,
    403 				inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
    404 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
    405 		   (tp->t_flags & CRTSCTS)) {
    406 		/* the line is up and we want to do rts/cts flow control */
    407 		if (stat & MSR_CTS) {
    408 			tp->t_state &=~ TS_TTSTOP;
    409 			ttstart(tp);
    410 		} else
    411 			tp->t_state |= TS_TTSTOP;
    412 	}
    413 }
    414 
    415 comioctl(dev, cmd, data, flag)
    416 	dev_t dev;
    417 	caddr_t data;
    418 {
    419 	register struct tty *tp;
    420 	register int unit = UNIT(dev);
    421 	register com;
    422 	register int error;
    423 
    424 	tp = &com_tty[unit];
    425 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
    426 	if (error >= 0)
    427 		return (error);
    428 	error = ttioctl(tp, cmd, data, flag);
    429 	if (error >= 0)
    430 		return (error);
    431 
    432 	com = com_addr[unit];
    433 	switch (cmd) {
    434 
    435 	case TIOCSBRK:
    436 		outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
    437 		break;
    438 
    439 	case TIOCCBRK:
    440 		outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
    441 		break;
    442 
    443 	case TIOCSDTR:
    444 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
    445 		break;
    446 
    447 	case TIOCCDTR:
    448 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
    449 		break;
    450 
    451 	case TIOCMSET:
    452 		(void) commctl(dev, *(int *)data, DMSET);
    453 		break;
    454 
    455 	case TIOCMBIS:
    456 		(void) commctl(dev, *(int *)data, DMBIS);
    457 		break;
    458 
    459 	case TIOCMBIC:
    460 		(void) commctl(dev, *(int *)data, DMBIC);
    461 		break;
    462 
    463 	case TIOCMGET:
    464 		*(int *)data = commctl(dev, 0, DMGET);
    465 		break;
    466 
    467 	default:
    468 		return (ENOTTY);
    469 	}
    470 	return (0);
    471 }
    472 
    473 comparam(tp, t)
    474 	register struct tty *tp;
    475 	register struct termios *t;
    476 {
    477 	register com;
    478 	register int cfcr, cflag = t->c_cflag;
    479 	int unit = UNIT(tp->t_dev);
    480 	int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
    481 
    482 	/* check requested parameters */
    483         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    484                 return(EINVAL);
    485         /* and copy to tty */
    486         tp->t_ispeed = t->c_ispeed;
    487         tp->t_ospeed = t->c_ospeed;
    488         tp->t_cflag = cflag;
    489 
    490 	com = com_addr[unit];
    491 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
    492 	if (ospeed == 0) {
    493 		(void) commctl(unit, 0, DMSET);	/* hang up line */
    494 		return(0);
    495 	}
    496 	outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
    497 	outb(com+com_data, ospeed & 0xFF);
    498 	outb(com+com_ier, ospeed >> 8);
    499 	switch (cflag&CSIZE) {
    500 	case CS5:
    501 		cfcr = CFCR_5BITS; break;
    502 	case CS6:
    503 		cfcr = CFCR_6BITS; break;
    504 	case CS7:
    505 		cfcr = CFCR_7BITS; break;
    506 	case CS8:
    507 		cfcr = CFCR_8BITS; break;
    508 	}
    509 	if (cflag&PARENB) {
    510 		cfcr |= CFCR_PENAB;
    511 		if ((cflag&PARODD) == 0)
    512 			cfcr |= CFCR_PEVEN;
    513 	}
    514 	if (cflag&CSTOPB)
    515 		cfcr |= CFCR_STOPB;
    516 	outb(com+com_cfcr, cfcr);
    517 
    518 	if (com_hasfifo & (1 << unit))
    519 		outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_4);
    520 
    521 	return(0);
    522 }
    523 
    524 comstart(tp)
    525 	register struct tty *tp;
    526 {
    527 	register com;
    528 	int s, unit, c;
    529 
    530 	unit = UNIT(tp->t_dev);
    531 	com = com_addr[unit];
    532 	s = spltty();
    533 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
    534 		goto out;
    535 	if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
    536 		if (tp->t_state&TS_ASLEEP) {
    537 			tp->t_state &= ~TS_ASLEEP;
    538 			wakeup((caddr_t)&tp->t_out);
    539 		}
    540 		if (tp->t_wsel) {
    541 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
    542 			tp->t_wsel = 0;
    543 			tp->t_state &= ~TS_WCOLL;
    544 		}
    545 	}
    546 	if (RB_LEN(&tp->t_out) == 0)
    547 		goto out;
    548 	if (inb(com+com_lsr) & LSR_TXRDY) {
    549 		c = getc(&tp->t_out);
    550 		tp->t_state |= TS_BUSY;
    551 		outb(com+com_data, c);
    552 		if (com_hasfifo & (1 << unit))
    553 			for (c = 1; c < 16 && RB_LEN(&tp->t_out); ++c)
    554 				outb(com+com_data, getc(&tp->t_out));
    555 	}
    556 out:
    557 	splx(s);
    558 }
    559 
    560 /*
    561  * Stop output on a line.
    562  */
    563 /*ARGSUSED*/
    564 comstop(tp, flag)
    565 	register struct tty *tp;
    566 {
    567 	register int s;
    568 
    569 	s = spltty();
    570 	if (tp->t_state & TS_BUSY) {
    571 		if ((tp->t_state&TS_TTSTOP)==0)
    572 			tp->t_state |= TS_FLUSH;
    573 	}
    574 	splx(s);
    575 }
    576 
    577 commctl(dev, bits, how)
    578 	dev_t dev;
    579 	int bits, how;
    580 {
    581 	register com;
    582 	register int unit;
    583 	int s;
    584 
    585 	unit = UNIT(dev);
    586 	com = com_addr[unit];
    587 	s = spltty();
    588 	switch (how) {
    589 
    590 	case DMSET:
    591 		outb(com+com_mcr, bits | MCR_IENABLE);
    592 		break;
    593 
    594 	case DMBIS:
    595 		outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
    596 		break;
    597 
    598 	case DMBIC:
    599 		outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
    600 		break;
    601 
    602 	case DMGET:
    603 		bits = inb(com+com_msr);
    604 		break;
    605 	}
    606 	(void) splx(s);
    607 	return(bits);
    608 }
    609 
    610 /*
    611  * Following are all routines needed for COM to act as console
    612  */
    613 #include "i386/i386/cons.h"
    614 
    615 comcnprobe(cp)
    616 	struct consdev *cp;
    617 {
    618 	int unit;
    619 
    620 	/* locate the major number */
    621 	for (commajor = 0; commajor < nchrdev; commajor++)
    622 		if (cdevsw[commajor].d_open == comopen)
    623 			break;
    624 
    625 	/* XXX: ick */
    626 	unit = CONUNIT;
    627 	com_addr[CONUNIT] = CONADDR;
    628 
    629 	/* make sure hardware exists?  XXX */
    630 
    631 	/* initialize required fields */
    632 	cp->cn_dev = makedev(commajor, unit);
    633 	cp->cn_tp = &com_tty[unit];
    634 #ifdef	COMCONSOLE
    635 	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
    636 #else
    637 	cp->cn_pri = CN_NORMAL;
    638 #endif
    639 }
    640 
    641 comcninit(cp)
    642 	struct consdev *cp;
    643 {
    644 	int unit = UNIT(cp->cn_dev);
    645 
    646 	cominit(unit, comdefaultrate);
    647 	comconsole = unit;
    648 	comconsinit = 1;
    649 }
    650 
    651 cominit(unit, rate)
    652 	int unit, rate;
    653 {
    654 	register int com;
    655 	int s;
    656 	short stat;
    657 
    658 #ifdef lint
    659 	stat = unit; if (stat) return;
    660 #endif
    661 	com = com_addr[unit];
    662 	s = splhigh();
    663 	outb(com+com_cfcr, CFCR_DLAB);
    664 	rate = ttspeedtab(comdefaultrate, comspeedtab);
    665 	outb(com+com_data, rate & 0xFF);
    666 	outb(com+com_ier, rate >> 8);
    667 	outb(com+com_cfcr, CFCR_8BITS);
    668 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
    669 	outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
    670 	stat = inb(com+com_iir);
    671 	splx(s);
    672 }
    673 
    674 comcngetc(dev)
    675 {
    676 	register com = com_addr[UNIT(dev)];
    677 	short stat;
    678 	int c, s;
    679 
    680 #ifdef lint
    681 	stat = dev; if (stat) return(0);
    682 #endif
    683 	s = splhigh();
    684 	while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
    685 		;
    686 	c = inb(com+com_data);
    687 	stat = inb(com+com_iir);
    688 	splx(s);
    689 	return(c);
    690 }
    691 
    692 /*
    693  * Console kernel output character routine.
    694  */
    695 comcnputc(dev, c)
    696 	dev_t dev;
    697 	register int c;
    698 {
    699 	register com = com_addr[UNIT(dev)];
    700 	register int timo;
    701 	short stat;
    702 	int s = splhigh();
    703 
    704 #ifdef lint
    705 	stat = dev; if (stat) return;
    706 #endif
    707 #ifdef KGDB
    708 	if (dev != kgdb_dev)
    709 #endif
    710 	if (comconsinit == 0) {
    711 		(void) cominit(UNIT(dev), comdefaultrate);
    712 		comconsinit = 1;
    713 	}
    714 	/* wait for any pending transmission to finish */
    715 	timo = 50000;
    716 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
    717 		;
    718 	outb(com+com_data, c);
    719 	/* wait for this transmission to complete */
    720 	timo = 1500000;
    721 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
    722 		;
    723 	/* clear any interrupts generated by this transmission */
    724 	stat = inb(com+com_iir);
    725 	splx(s);
    726 }
    727 
    728 int
    729 comselect(dev, rw, p)
    730 	dev_t dev;
    731 	int rw;
    732 	struct proc *p;
    733 {
    734 	register struct tty *tp = &com_tty[UNIT(dev)];
    735 	int nread;
    736 	int s = spltty();
    737         struct proc *selp;
    738 
    739 	switch (rw) {
    740 
    741 	case FREAD:
    742 		nread = ttnread(tp);
    743 		if (nread > 0 ||
    744 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
    745 			goto win;
    746 		if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
    747 			tp->t_state |= TS_RCOLL;
    748 		else
    749 			tp->t_rsel = p->p_pid;
    750 		break;
    751 
    752 	case FWRITE:
    753 		if (RB_LEN(&tp->t_out) <= tp->t_lowat)
    754 			goto win;
    755 		if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
    756 			tp->t_state |= TS_WCOLL;
    757 		else
    758 			tp->t_wsel = p->p_pid;
    759 		break;
    760 	}
    761 	splx(s);
    762 	return (0);
    763   win:
    764 	splx(s);
    765 	return (1);
    766 }
    767 
    768 #endif
    769