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