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