Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.23
      1 /*	$NetBSD: ser.c,v 1.23 1994/10/26 02:04:51 cgd Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  *	@(#)ser.c	7.12 (Berkeley) 6/27/91
     36  */
     37 /*
     38  * XXX This file needs major cleanup it will never ervice more than one
     39  * XXX unit.
     40  */
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/ioctl.h>
     45 #include <sys/device.h>
     46 #include <sys/tty.h>
     47 #include <sys/proc.h>
     48 #include <sys/conf.h>
     49 #include <sys/file.h>
     50 #include <sys/malloc.h>
     51 #include <sys/uio.h>
     52 #include <sys/kernel.h>
     53 #include <sys/syslog.h>
     54 #include <sys/queue.h>
     55 #include <machine/cpu.h>
     56 #include <amiga/amiga/device.h>
     57 #include <amiga/dev/serreg.h>
     58 #include <amiga/amiga/custom.h>
     59 #include <amiga/amiga/cia.h>
     60 #include <amiga/amiga/cc.h>
     61 
     62 #include <dev/cons.h>
     63 
     64 #include "ser.h"
     65 #if NSER > 0
     66 
     67 void serattach __P((struct device *, struct device *, void *));
     68 int sermatch __P((struct device *, struct cfdata *, void *));
     69 
     70 struct cfdriver sercd = {
     71 	NULL, "ser", sermatch, serattach, DV_TTY,
     72 	sizeof(struct device), NULL, 0 };
     73 
     74 #define SEROBUF_SIZE 32
     75 #define SERIBUF_SIZE 512
     76 
     77 int	serstart(), serparam(), serintr(), serhwiflow();
     78 int	ser_active;
     79 int	ser_hasfifo;
     80 int	nser = NSER;
     81 #ifdef SERCONSOLE
     82 int	serconsole = SERCONSOLE;
     83 #else
     84 int	serconsole = -1;
     85 #endif
     86 int	serconsinit;
     87 int	serdefaultrate = TTYDEF_SPEED;
     88 int	sermajor;
     89 int	serswflags;
     90 #define SWFLAGS(dev) (serswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
     91 
     92 struct	vbl_node ser_vbl_node[NSER];
     93 struct	tty ser_cons;
     94 struct	tty *ser_tty[NSER];
     95 
     96 struct speedtab serspeedtab[] = {
     97 	0,	0,
     98 	50,	SERBRD(50),
     99 	75,	SERBRD(75),
    100 	110,	SERBRD(110),
    101 	134,	SERBRD(134),
    102 	150,	SERBRD(150),
    103 	200,	SERBRD(200),
    104 	300,	SERBRD(300),
    105 	600,	SERBRD(600),
    106 	1200,	SERBRD(1200),
    107 	1800,	SERBRD(1800),
    108 	2400,	SERBRD(2400),
    109 	4800,	SERBRD(4800),
    110 	9600,	SERBRD(9600),
    111 	19200,	SERBRD(19200),
    112 	38400,	SERBRD(38400),
    113 	57600,	SERBRD(57600),
    114 	76800,	SERBRD(76800),
    115 	115200,	SERBRD(115200),
    116 	-1,	-1
    117 };
    118 
    119 
    120 /*
    121  * Since this UART is not particularly bright (to put it nicely), we'll
    122  * have to do parity stuff on our own.	This table contains the 8th bit
    123  * in 7bit character mode, for even parity.  If you want odd parity,
    124  * flip the bit.  (for generation of the table, see genpar.c)
    125  */
    126 
    127 u_char	even_parity[] = {
    128 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    129 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    130 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    131 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    132 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    133 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    134 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    135 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    136 };
    137 
    138 /*
    139  * Since we don't get interrupts for changes on the modem control line,
    140  * we'll have to fake them by comparing current settings to the settings
    141  * we remembered on last invocation.
    142  */
    143 
    144 u_char	last_ciab_pra;
    145 
    146 extern struct tty *constty;
    147 
    148 #ifdef KGDB
    149 #include <machine/remote-sl.h>
    150 
    151 extern dev_t kgdb_dev;
    152 extern int kgdb_rate;
    153 extern int kgdb_debug_init;
    154 #endif
    155 
    156 #ifdef DEBUG
    157 long	fifoin[17];
    158 long	fifoout[17];
    159 long	serintrcount[16];
    160 long	sermintcount[16];
    161 #endif
    162 
    163 void	sermint __P((register int unit));
    164 
    165 int
    166 sermatch(pdp, cfp, auxp)
    167 	struct device *pdp;
    168 	struct cfdata *cfp;
    169 	void *auxp;
    170 {
    171 	if (matchname("ser", (char *)auxp) == 0 || cfp->cf_unit != 0)
    172 		return(0);
    173 	if (serconsole != 0 && amiga_realconfig == 0)
    174 		return(0);
    175 	return(1);
    176 }
    177 
    178 
    179 void
    180 serattach(pdp, dp, auxp)
    181 	struct device *pdp, *dp;
    182 	void *auxp;
    183 {
    184 	u_short ir;
    185 
    186 	ir = custom.intenar;
    187 	if (serconsole == 0)
    188 		DELAY(100000);
    189 
    190 	ser_active |= 1;
    191 	ser_vbl_node[0].function = (void (*) (void *)) sermint;
    192 	add_vbl_function(&ser_vbl_node[0], SER_VBL_PRIORITY, (void *) 0);
    193 #ifdef KGDB
    194 	if (kgdb_dev == makedev(sermajor, 0)) {
    195 		if (serconsole == 0)
    196 			kgdb_dev = NODEV; /* can't debug over console port */
    197 		else {
    198 			(void) serinit(0, kgdb_rate);
    199 			serconsinit = 1;       /* don't re-init in serputc */
    200 			if (kgdb_debug_init == 0)
    201 				printf(" kgdb enabled\n");
    202 			else {
    203 				/*
    204 				 * Print prefix of device name,
    205 				 * let kgdb_connect print the rest.
    206 				 */
    207 				printf("ser0: ");
    208 				kgdb_connect(1);
    209 			}
    210 		}
    211 	}
    212 #endif
    213 	/*
    214 	 * Need to reset baud rate, etc. of next print so reset serconsinit.
    215 	 */
    216 	if (0 == serconsole)
    217 		serconsinit = 0;
    218 	if (dp)
    219 		printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE,
    220 		    SEROBUF_SIZE);
    221 }
    222 
    223 
    224 /* ARGSUSED */
    225 int
    226 seropen(dev, flag, mode, p)
    227 	dev_t dev;
    228 	int flag, mode;
    229 	struct proc *p;
    230 {
    231 	struct tty *tp;
    232 	int unit, error, s;
    233 
    234 	error = 0;
    235 	unit = SERUNIT(dev);
    236 
    237 	if (unit >= NSER || (ser_active & (1 << unit)) == 0)
    238 		return (ENXIO);
    239 
    240 	s = spltty();
    241 
    242 	if (ser_tty[unit])
    243 		tp = ser_tty[unit];
    244 	else
    245 		tp = ser_tty[unit] = ttymalloc();
    246 
    247 	tp->t_oproc = (void (*) (struct tty *)) serstart;
    248 	tp->t_param = serparam;
    249 	tp->t_dev = dev;
    250 	tp->t_hwiflow = serhwiflow;
    251 
    252 	if ((tp->t_state & TS_ISOPEN) == 0) {
    253 		tp->t_state |= TS_WOPEN;
    254 		ttychars(tp);
    255 		if (tp->t_ispeed == 0) {
    256 			/*
    257 			 * only when cleared do we reset to defaults.
    258 			 */
    259 			tp->t_iflag = TTYDEF_IFLAG;
    260 			tp->t_oflag = TTYDEF_OFLAG;
    261 			tp->t_cflag = TTYDEF_CFLAG;
    262 			tp->t_lflag = TTYDEF_LFLAG;
    263 			tp->t_ispeed = tp->t_ospeed = serdefaultrate;
    264 		}
    265 		/*
    266 		 * do these all the time
    267 		 */
    268 		if (serswflags & TIOCFLAG_CLOCAL)
    269 			tp->t_cflag |= CLOCAL;
    270 		if (serswflags & TIOCFLAG_CRTSCTS)
    271 			tp->t_cflag |= CRTSCTS;
    272 		if (serswflags & TIOCFLAG_MDMBUF)
    273 			tp->t_cflag |= MDMBUF;
    274 		serparam(tp, &tp->t_termios);
    275 		ttsetwater(tp);
    276 
    277 		(void)sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    278 		if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
    279 		    (sermctl(dev, 0, DMGET) & TIOCM_CD))
    280 			tp->t_state |= TS_CARR_ON;
    281 		else
    282 			tp->t_state &= ~TS_CARR_ON;
    283 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
    284 		splx(s);
    285 		return(EBUSY);
    286 	}
    287 
    288 	/*
    289 	 * if NONBLOCK requested, ignore carrier
    290 	 */
    291 	if (flag & O_NONBLOCK)
    292 		goto done;
    293 
    294 	/*
    295 	 * block waiting for carrier
    296 	 */
    297 	while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
    298 		tp->t_state |= TS_WOPEN;
    299 		error = ttysleep(tp, (caddr_t)&tp->t_rawq,
    300 		    TTIPRI | PCATCH, ttopen, 0);
    301 		if (error) {
    302 			splx(s);
    303 			return(error);
    304 		}
    305 	}
    306 done:
    307 	/* This is a way to handle lost XON characters */
    308 	if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
    309 		tp->t_state &= ~TS_TTSTOP;
    310 	        ttstart (tp);
    311 	}
    312 
    313 	splx(s);
    314 	/*
    315 	 * Reset the tty pointer, as there could have been a dialout
    316 	 * use of the tty with a dialin open waiting.
    317 	 */
    318 	tp->t_dev = dev;
    319 	return((*linesw[tp->t_line].l_open)(dev, tp));
    320 }
    321 
    322 /*ARGSUSED*/
    323 int
    324 serclose(dev, flag, mode, p)
    325 	dev_t dev;
    326 	int flag, mode;
    327 	struct proc *p;
    328 {
    329 	struct tty *tp;
    330 	int unit;
    331 
    332 	unit = SERUNIT(dev);
    333 
    334 	tp = ser_tty[unit];
    335 	(*linesw[tp->t_line].l_close)(tp, flag);
    336 	custom.adkcon = ADKCONF_UARTBRK;	/* clear break */
    337 #ifdef KGDB
    338 	/*
    339 	 * do not disable interrupts if debugging
    340 	 */
    341 	if (dev != kgdb_dev)
    342 #endif
    343 		custom.intena = INTF_RBF | INTF_TBE;	/* disable interrups */
    344 	custom.intreq = INTF_RBF | INTF_TBE;		/* clear intr request */
    345 
    346 	/*
    347 	 * If the device is closed, it's close, no matter whether we deal with
    348 	 * modem control signals nor not.
    349 	 */
    350 #if 0
    351 	if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
    352 	    (tp->t_state & TS_ISOPEN) == 0)
    353 #endif
    354 		(void) sermctl(dev, 0, DMSET);
    355 	ttyclose(tp);
    356 #if not_yet
    357 	if (tp != &ser_cons) {
    358 		remove_vbl_function(&ser_vbl_node[unit]);
    359 		ttyfree(tp);
    360 		ser_tty[unit] = (struct tty *) NULL;
    361 	}
    362 #endif
    363 	return (0);
    364 }
    365 
    366 int
    367 serread(dev, uio, flag)
    368 	dev_t dev;
    369 	struct uio *uio;
    370 	int flag;
    371 {
    372 	struct tty *tp;
    373 	if ((tp = ser_tty[SERUNIT(dev)]) == NULL)
    374 		return(ENXIO);
    375 	return((*linesw[tp->t_line].l_read)(tp, uio, flag));
    376 }
    377 
    378 int
    379 serwrite(dev, uio, flag)
    380 	dev_t dev;
    381 	struct uio *uio;
    382 	int flag;
    383 {
    384 	struct tty *tp;
    385 
    386 	if((tp = ser_tty[SERUNIT(dev)]) == NULL)
    387 		return(ENXIO);
    388 	return((*linesw[tp->t_line].l_write)(tp, uio, flag));
    389 }
    390 
    391 
    392 /*
    393  * We don't do any processing of data here, so we store the raw code
    394  * obtained from the uart register.  In theory, 110kBaud gives you
    395  * 11kcps, so 16k buffer should be more than enough, interrupt
    396  * latency of 1s should never happen, or something is seriously
    397  * wrong..
    398  */
    399 
    400 static u_short serbuf[SERIBUF_SIZE];
    401 static u_short *sbrpt = serbuf;
    402 static u_short *sbwpt = serbuf;
    403 static u_short sbcnt;
    404 static u_short sbovfl;
    405 
    406 /*
    407  * This is a replacement for the lack of a hardware fifo.  32k should be
    408  * enough (there's only one unit anyway, so this is not going to
    409  * accumulate).
    410  */
    411 void
    412 ser_fastint()
    413 {
    414 	/*
    415 	 * We're at RBE-level, which is higher than VBL-level which is used
    416 	 * to periodically transmit contents of this buffer up one layer,
    417 	 * so no spl-raising is necessary.
    418 	 */
    419 	register u_short ints, code;
    420 
    421 	ints = custom.intreqr & INTF_RBF;
    422 	if (ints == 0)
    423 		return;
    424 
    425 	/*
    426 	 * clear interrupt
    427 	 */
    428 	custom.intreq = ints;
    429 
    430 	/*
    431 	 * this register contains both data and status bits!
    432 	 */
    433 	code = custom.serdatr;
    434 
    435 	/*
    436 	 * check for buffer overflow.
    437 	 */
    438 	if (sbcnt == SERIBUF_SIZE) {
    439 		++sbovfl;
    440 		return;
    441 	}
    442 	/*
    443 	 * store in buffer
    444 	 */
    445 	*sbwpt++ = code;
    446 	if (sbwpt == serbuf + SERIBUF_SIZE)
    447 		sbwpt = serbuf;
    448 	++sbcnt;
    449 	if (sbcnt > SERIBUF_SIZE - 4)
    450 		CLRRTS(ciab.pra);	/* drop RTS if buffer almost full */
    451 }
    452 
    453 
    454 int
    455 serintr(unit)
    456 	int unit;
    457 {
    458 	int s1, s2, ovfl;
    459 	struct tty *tp = ser_tty[unit];
    460 
    461 	/*
    462 	 * Make sure we're not interrupted by another
    463 	 * vbl, but allow level5 ints
    464 	 */
    465 	s1 = spltty();
    466 
    467 	/*
    468 	 * pass along any acumulated information
    469 	 */
    470 	while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
    471 		/*
    472 		 * no collision with ser_fastint()
    473 		 */
    474 		sereint(unit, *sbrpt++);
    475 
    476 		ovfl = 0;
    477 		/* lock against ser_fastint() */
    478 		s2 = spl5();
    479 		sbcnt--;
    480 		if (sbrpt == serbuf + SERIBUF_SIZE)
    481 			sbrpt = serbuf;
    482 		if (sbovfl != 0) {
    483 			ovfl = sbovfl;
    484 			sbovfl = 0;
    485 		}
    486 		splx(s2);
    487 		if (ovfl != 0)
    488 			log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
    489 			    ovfl);
    490 	}
    491 	if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
    492 		SETRTS(ciab.pra);	/* start accepting data again */
    493 	splx(s1);
    494 }
    495 
    496 int
    497 sereint(unit, stat)
    498 	int unit, stat;
    499 {
    500 	struct tty *tp;
    501 	u_char ch;
    502 	int c;
    503 
    504 	tp = ser_tty[unit];
    505 	ch = stat & 0xff;
    506 	c = ch;
    507 
    508 	if ((tp->t_state & TS_ISOPEN) == 0) {
    509 #ifdef KGDB
    510 		/* we don't care about parity errors */
    511 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
    512 			kgdb_connect(0);	/* trap into kgdb */
    513 #endif
    514 		return;
    515 	}
    516 
    517 	/*
    518 	 * Check for break and (if enabled) parity error.
    519 	 */
    520 	if ((stat & 0x1ff) == 0)
    521 		c |= TTY_FE;
    522 	else if ((tp->t_cflag & PARENB) &&
    523 		    (((ch >> 7) + even_parity[ch & 0x7f]
    524 		    + !!(tp->t_cflag & PARODD)) & 1))
    525 			c |= TTY_PE;
    526 
    527 	if (stat & SERDATRF_OVRUN)
    528 		log(LOG_WARNING, "ser0: silo overflow\n");
    529 
    530 	(*linesw[tp->t_line].l_rint)(c, tp);
    531 }
    532 
    533 /*
    534  * This interrupt is periodically invoked in the vertical blank
    535  * interrupt.  It's used to keep track of the modem control lines
    536  * and (new with the fast_int code) to move accumulated data
    537  * up into the tty layer.
    538  */
    539 void
    540 sermint(unit)
    541 	int unit;
    542 {
    543 	struct tty *tp;
    544 	u_char stat, last, istat;
    545 
    546 	tp = ser_tty[unit];
    547 	if (!tp)
    548 		return;
    549 
    550 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
    551 		sbrpt = sbwpt = serbuf;
    552 		return;
    553 	}
    554 	/*
    555 	 * empty buffer
    556 	 */
    557 	serintr(unit);
    558 
    559 	stat = ciab.pra;
    560 	last = last_ciab_pra;
    561 	last_ciab_pra = stat;
    562 
    563 	/*
    564 	 * check whether any interesting signal changed state
    565 	 */
    566 	istat = stat ^ last;
    567 
    568 	if ((istat & CIAB_PRA_CD) &&
    569 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
    570 		if (ISDCD(stat))
    571 			(*linesw[tp->t_line].l_modem)(tp, 1);
    572 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
    573 			CLRDTR(stat);
    574 			CLRRTS(stat);
    575 			ciab.pra = stat;
    576 			last_ciab_pra = stat;
    577 		}
    578 	}
    579 	if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
    580 	    (tp->t_cflag & CRTSCTS)) {
    581 #if 0
    582 		/* the line is up and we want to do rts/cts flow control */
    583 		if (ISCTS(stat)) {
    584 			tp->t_state &= ~TS_TTSTOP;
    585 			ttstart(tp);
    586 			/* cause tbe-int if we were stuck there */
    587 			custom.intreq = INTF_SETCLR | INTF_TBE;
    588 		} else
    589 			tp->t_state |= TS_TTSTOP;
    590 #else
    591 		/* do this on hardware level, not with tty driver */
    592 		if (ISCTS(stat)) {
    593 			tp->t_state &= ~TS_TTSTOP;
    594 			/* cause TBE interrupt */
    595 			custom.intreq = INTF_SETCLR | INTF_TBE;
    596 		}
    597 #endif
    598 	}
    599 }
    600 
    601 int
    602 serioctl(dev, cmd, data, flag, p)
    603 	dev_t	dev;
    604 	caddr_t data;
    605 	struct proc *p;
    606 {
    607 	register struct tty *tp;
    608 	register int unit = SERUNIT(dev);
    609 	register int error;
    610 
    611 	tp = ser_tty[unit];
    612 	if (!tp)
    613 		return ENXIO;
    614 
    615 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    616 	if (error >= 0)
    617 		return(error);
    618 
    619 	error = ttioctl(tp, cmd, data, flag, p);
    620 	if (error >= 0)
    621 		return(error);
    622 
    623 	switch (cmd) {
    624 	case TIOCSBRK:
    625 		custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
    626 		break;
    627 
    628 	case TIOCCBRK:
    629 		custom.adkcon = ADKCONF_UARTBRK;
    630 		break;
    631 
    632 	case TIOCSDTR:
    633 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    634 		break;
    635 
    636 	case TIOCCDTR:
    637 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    638 		break;
    639 
    640 	case TIOCMSET:
    641 		(void) sermctl(dev, *(int *) data, DMSET);
    642 		break;
    643 
    644 	case TIOCMBIS:
    645 		(void) sermctl(dev, *(int *) data, DMBIS);
    646 		break;
    647 
    648 	case TIOCMBIC:
    649 		(void) sermctl(dev, *(int *) data, DMBIC);
    650 		break;
    651 
    652 	case TIOCMGET:
    653 		*(int *)data = sermctl(dev, 0, DMGET);
    654 		break;
    655 	case TIOCGFLAGS:
    656 		*(int *)data = SWFLAGS(dev);
    657 		break;
    658 	case TIOCSFLAGS:
    659 		error = suser(p->p_ucred, &p->p_acflag);
    660 		if (error != 0)
    661 			return(EPERM);
    662 
    663 		serswflags = *(int *)data;
    664                 serswflags &= /* only allow valid flags */
    665                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
    666 		break;
    667 	default:
    668 		return(ENOTTY);
    669 	}
    670 
    671 	return(0);
    672 }
    673 
    674 int
    675 serparam(tp, t)
    676 	struct tty *tp;
    677 	struct termios *t;
    678 {
    679 	int cfcr, cflag, unit, ospeed;
    680 
    681 	cflag = t->c_cflag;
    682 	unit = SERUNIT(tp->t_dev);
    683 	ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
    684 
    685 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    686 		return(EINVAL);
    687 
    688 	/*
    689 	 * copy to tty
    690 	 */
    691 	tp->t_ispeed = t->c_ispeed;
    692 	tp->t_ospeed = t->c_ospeed;
    693 	tp->t_cflag = cflag;
    694 
    695 	/*
    696 	 * enable interrupts
    697 	 */
    698 	custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
    699 	last_ciab_pra = ciab.pra;
    700 
    701 	if (ospeed == 0)
    702 		(void)sermctl(tp->t_dev, 0, DMSET);	/* hang up line */
    703 	else {
    704 		/*
    705 		 * (re)enable DTR
    706 		 * and set baud rate. (8 bit mode)
    707 		 */
    708 		(void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    709 		custom.serper = (0 << 15) | ospeed;
    710 	}
    711 	return(0);
    712 }
    713 
    714 int serhwiflow(tp, flag)
    715         struct tty *tp;
    716         int flag;
    717 {
    718 #if 0
    719 	printf ("serhwiflow %d\n", flag);
    720 #endif
    721         if (flag)
    722 		CLRRTS(ciab.pra);
    723 	else
    724 	        SETRTS(ciab.pra);
    725         return 1;
    726 }
    727 
    728 static void
    729 ser_putchar(tp, c)
    730 	struct tty *tp;
    731 	u_short c;
    732 {
    733 	if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
    734 		c &= 0x7f;
    735 
    736 	/*
    737 	 * handle parity if necessary
    738 	 */
    739 	if (tp->t_cflag & PARENB) {
    740 		if (even_parity[c])
    741 			c |= 0x80;
    742 		if (tp->t_cflag & PARODD)
    743 			c ^= 0x80;
    744 	}
    745 	/*
    746 	 * add stop bit(s)
    747 	 */
    748 	if (tp->t_cflag & CSTOPB)
    749 		c |= 0x300;
    750 	else
    751 		c |= 0x100;
    752 
    753 	custom.serdat = c;
    754 }
    755 
    756 
    757 static u_char ser_outbuf[SEROBUF_SIZE];
    758 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
    759 
    760 void
    761 ser_outintr()
    762 {
    763 	struct tty *tp = ser_tty[0];
    764 	u_short c;
    765 	int s;
    766 
    767 	tp = ser_tty[0];
    768 	s = spltty();
    769 
    770 	if (tp == 0)
    771 		goto out;
    772 
    773 	if ((custom.intreqr & INTF_TBE) == 0)
    774 		goto out;
    775 
    776 	/*
    777 	 * clear interrupt
    778 	 */
    779 	custom.intreq = INTF_TBE;
    780 
    781 	if (sob_ptr == sob_end) {
    782 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    783 		if (tp->t_line)
    784 			(*linesw[tp->t_line].l_start)(tp);
    785 		else
    786 			serstart(tp);
    787 		goto out;
    788 	}
    789 
    790 	/*
    791 	 * Do hardware flow control here.  if the CTS line goes down, don't
    792 	 * transmit anything.  That way, we'll be restarted by the periodic
    793 	 * interrupt when CTS comes back up.
    794 	 */
    795 	if (ISCTS(ciab.pra))
    796 		ser_putchar(tp, *sob_ptr++);
    797 	else
    798 		CLRCTS(last_ciab_pra);	/* Remember that CTS is off */
    799 out:
    800 	splx(s);
    801 }
    802 
    803 int
    804 serstart(tp)
    805 	struct tty *tp;
    806 {
    807 	int cc, s, unit, hiwat;
    808 
    809 	hiwat = 0;
    810 
    811 	if ((tp->t_state & TS_ISOPEN) == 0)
    812 		return;
    813 
    814 	unit = SERUNIT(tp->t_dev);
    815 
    816 	s = spltty();
    817 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    818 		goto out;
    819 
    820 	cc = tp->t_outq.c_cc;
    821 	if (cc <= tp->t_lowat) {
    822 		if (tp->t_state & TS_ASLEEP) {
    823 			tp->t_state &= ~TS_ASLEEP;
    824 			wakeup((caddr_t) & tp->t_outq);
    825 		}
    826 		selwakeup(&tp->t_wsel);
    827 	}
    828 	if (cc == 0 || (tp->t_state & TS_BUSY))
    829 		goto out;
    830 
    831 	/*
    832 	 * We only do bulk transfers if using CTSRTS flow control, not for
    833 	 * (probably sloooow) ixon/ixoff devices.
    834 	 */
    835 	if ((tp->t_cflag & CRTSCTS) == 0)
    836 		cc = 1;
    837 
    838 	/*
    839 	 * Limit the amount of output we do in one burst
    840 	 * to prevent hogging the CPU.
    841 	 */
    842 	if (cc > SEROBUF_SIZE) {
    843 		hiwat++;
    844 		cc = SEROBUF_SIZE;
    845 	}
    846 	cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
    847 	if (cc > 0) {
    848 		tp->t_state |= TS_BUSY;
    849 
    850 		sob_ptr = ser_outbuf;
    851 		sob_end = ser_outbuf + cc;
    852 
    853 		/*
    854 		 * Get first character out, then have TBE-interrupts blow out
    855 		 * further characters, until buffer is empty, and TS_BUSY gets
    856 		 * cleared.
    857 		 */
    858 		ser_putchar(tp, *sob_ptr++);
    859 	}
    860 out:
    861 	splx(s);
    862 }
    863 
    864 /*
    865  * Stop output on a line.
    866  */
    867 /*ARGSUSED*/
    868 int
    869 serstop(tp, flag)
    870 	struct tty *tp;
    871 {
    872 	int s;
    873 
    874 	s = spltty();
    875 	if (tp->t_state & TS_BUSY) {
    876 		if ((tp->t_state & TS_TTSTOP) == 0)
    877 			tp->t_state |= TS_FLUSH;
    878 	}
    879 	splx(s);
    880 }
    881 
    882 int
    883 sermctl(dev, bits, how)
    884 	dev_t dev;
    885 	int bits, how;
    886 {
    887 	int unit, s;
    888 	u_char ub;
    889 
    890 	unit = SERUNIT(dev);
    891 
    892 	/*
    893 	 * convert TIOCM* mask into CIA mask
    894 	 * which is active low
    895 	 */
    896 	if (how != DMGET) {
    897 		ub = 0;
    898 		if (bits & TIOCM_DTR)
    899 			ub |= CIAB_PRA_DTR;
    900 		if (bits & TIOCM_RTS)
    901 			ub |= CIAB_PRA_RTS;
    902 		if (bits & TIOCM_CTS)
    903 			ub |= CIAB_PRA_CTS;
    904 		if (bits & TIOCM_CD)
    905 			ub |= CIAB_PRA_CD;
    906 		if (bits & TIOCM_RI)
    907 			ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    908 		if (bits & TIOCM_DSR)
    909 			ub |= CIAB_PRA_DSR;
    910 	}
    911 	s = spltty();
    912 	switch (how) {
    913 	case DMSET:
    914 		/* invert and set */
    915 		ciab.pra = ~ub;
    916 		break;
    917 
    918 	case DMBIC:
    919 		ciab.pra |= ub;
    920 		ub = ~ciab.pra;
    921 		break;
    922 
    923 	case DMBIS:
    924 		ciab.pra &= ~ub;
    925 		ub = ~ciab.pra;
    926 		break;
    927 
    928 	case DMGET:
    929 		ub = ~ciab.pra;
    930 		break;
    931 	}
    932 	(void)splx(s);
    933 
    934 	bits = 0;
    935 	if (ub & CIAB_PRA_DTR)
    936 		bits |= TIOCM_DTR;
    937 	if (ub & CIAB_PRA_RTS)
    938 		bits |= TIOCM_RTS;
    939 	if (ub & CIAB_PRA_CTS)
    940 		bits |= TIOCM_CTS;
    941 	if (ub & CIAB_PRA_CD)
    942 		bits |= TIOCM_CD;
    943 	if (ub & CIAB_PRA_SEL)
    944 		bits |= TIOCM_RI;
    945 	if (ub & CIAB_PRA_DSR)
    946 		bits |= TIOCM_DSR;
    947 
    948 	return(bits);
    949 }
    950 
    951 /*
    952  * Following are all routines needed for SER to act as console
    953  */
    954 int
    955 sercnprobe(cp)
    956 	struct consdev *cp;
    957 {
    958 	int unit = CONUNIT;
    959 
    960 	/* locate the major number */
    961 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
    962 		if (cdevsw[sermajor].d_open == (void *)seropen)
    963 			break;
    964 
    965 
    966 	unit = CONUNIT;			/* XXX: ick */
    967 
    968 	/*
    969 	 * initialize required fields
    970 	 */
    971 	cp->cn_dev = makedev(sermajor, unit);
    972 	if (serconsole == unit)
    973 		cp->cn_pri = CN_REMOTE;
    974 	else
    975 		cp->cn_pri = CN_NORMAL;
    976 #ifdef KGDB
    977 	if (major(kgdb_dev) == 1)	/* XXX */
    978 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
    979 #endif
    980 }
    981 
    982 sercninit(cp)
    983 	struct consdev *cp;
    984 {
    985 	int unit;
    986 
    987 	unit = SERUNIT(cp->cn_dev);
    988 
    989 	serinit(unit, serdefaultrate);
    990 	serconsole = unit;
    991 	serconsinit = 1;
    992 }
    993 
    994 serinit(unit, rate)
    995 	int unit, rate;
    996 {
    997 	int s;
    998 
    999 	s = splhigh();
   1000 	/*
   1001 	 * might want to fiddle with the CIA later ???
   1002 	 */
   1003 	custom.serper = ttspeedtab(rate, serspeedtab);
   1004 	splx(s);
   1005 }
   1006 
   1007 sercngetc(dev)
   1008 {
   1009 	u_short stat;
   1010 	int c, s;
   1011 
   1012 	s = splhigh();
   1013 	/*
   1014 	 * poll
   1015 	 */
   1016 	while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
   1017 		;
   1018 	c = stat & 0xff;
   1019 	/*
   1020 	 * clear interrupt
   1021 	 */
   1022 	custom.intreq = INTF_RBF;
   1023 	splx(s);
   1024 	return(c);
   1025 }
   1026 
   1027 /*
   1028  * Console kernel output character routine.
   1029  */
   1030 sercnputc(dev, c)
   1031 	dev_t dev;
   1032 	int c;
   1033 {
   1034 	register int timo;
   1035 	short stat;
   1036 	int s;
   1037 
   1038 	s = splhigh();
   1039 
   1040 	if (serconsinit == 0) {
   1041 		(void)serinit(SERUNIT(dev), serdefaultrate);
   1042 		serconsinit = 1;
   1043 	}
   1044 
   1045 	/*
   1046 	 * wait for any pending transmission to finish
   1047 	 */
   1048 	timo = 50000;
   1049 	while (!(custom.serdatr & SERDATRF_TBE) && --timo);
   1050 
   1051 	/*
   1052 	 * transmit char.
   1053 	 */
   1054 	custom.serdat = (c & 0xff) | 0x100;
   1055 
   1056 	/*
   1057 	 * wait for this transmission to complete
   1058 	 */
   1059 	timo = 1500000;
   1060 	while (!(custom.serdatr & SERDATRF_TBE) && --timo)
   1061 		;
   1062 
   1063 	/*
   1064 	 * Wait for the device (my vt100..) to process the data, since we
   1065 	 * don't do flow-control with cnputc
   1066 	 */
   1067 	for (timo = 0; timo < 30000; timo++)
   1068 		;
   1069 
   1070 	/*
   1071 	 * clear any interrupts generated by this transmission
   1072 	 */
   1073 	custom.intreq = INTF_TBE;
   1074 	splx(s);
   1075 }
   1076 #endif
   1077