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