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