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