Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.41
      1 /*	$NetBSD: ser.c,v 1.41 1997/09/21 17:21:24 is 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 #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 	return((*linesw[tp->t_line].l_open)(dev, tp));
    332 }
    333 
    334 /*ARGSUSED*/
    335 int
    336 serclose(dev, flag, mode, p)
    337 	dev_t dev;
    338 	int flag, mode;
    339 	struct proc *p;
    340 {
    341 	struct tty *tp;
    342 	int unit;
    343 	int closebits;
    344 
    345 	unit = SERUNIT(dev);
    346 
    347 	tp = ser_tty[unit];
    348 	(*linesw[tp->t_line].l_close)(tp, flag);
    349 	custom.adkcon = ADKCONF_UARTBRK;	/* clear break */
    350 #ifdef KGDB
    351 	/*
    352 	 * do not disable interrupts if debugging
    353 	 */
    354 	if (dev != kgdb_dev)
    355 #endif
    356 		custom.intena = INTF_RBF | INTF_TBE;	/* disable interrups */
    357 	custom.intreq = INTF_RBF | INTF_TBE;		/* clear intr request */
    358 
    359 	/*
    360 	 * If HUPCL is not set, leave DTR unchanged.
    361 	 */
    362 	if (tp->t_cflag & HUPCL)
    363 		closebits = 0;
    364 	else
    365 		closebits = sermctl(dev, 0, DMGET) & TIOCM_DTR;
    366 
    367 	(void) sermctl(dev, closebits, DMSET);
    368 
    369 	/*
    370 	 * Idea from dev/isa/com.c:
    371 	 * sleep a bit so that other side will notice, even if we reopen
    372 	 * immediately.
    373 	 */
    374 	(void) tsleep(tp, TTIPRI, ttclos, hz);
    375 	ttyclose(tp);
    376 #if not_yet
    377 	if (tp != &ser_cons) {
    378 		remove_vbl_function(&ser_vbl_node[unit]);
    379 		ttyfree(tp);
    380 		ser_tty[unit] = (struct tty *) NULL;
    381 	}
    382 #endif
    383 	return (0);
    384 }
    385 
    386 int
    387 serread(dev, uio, flag)
    388 	dev_t dev;
    389 	struct uio *uio;
    390 	int flag;
    391 {
    392 	struct tty *tp;
    393 	if ((tp = ser_tty[SERUNIT(dev)]) == NULL)
    394 		return(ENXIO);
    395 	return((*linesw[tp->t_line].l_read)(tp, uio, flag));
    396 }
    397 
    398 int
    399 serwrite(dev, uio, flag)
    400 	dev_t dev;
    401 	struct uio *uio;
    402 	int flag;
    403 {
    404 	struct tty *tp;
    405 
    406 	if((tp = ser_tty[SERUNIT(dev)]) == NULL)
    407 		return(ENXIO);
    408 	return((*linesw[tp->t_line].l_write)(tp, uio, flag));
    409 }
    410 
    411 struct tty *
    412 sertty(dev)
    413 	dev_t dev;
    414 {
    415 	return (ser_tty[SERUNIT(dev)]);
    416 }
    417 
    418 /*
    419  * We don't do any processing of data here, so we store the raw code
    420  * obtained from the uart register.  In theory, 110kBaud gives you
    421  * 11kcps, so 16k buffer should be more than enough, interrupt
    422  * latency of 1s should never happen, or something is seriously
    423  * wrong..
    424  */
    425 
    426 static u_short serbuf[SERIBUF_SIZE];
    427 static u_short *sbrpt = serbuf;
    428 static u_short *sbwpt = serbuf;
    429 static u_short sbcnt;
    430 static u_short sbovfl;
    431 
    432 /*
    433  * This is a replacement for the lack of a hardware fifo.  32k should be
    434  * enough (there's only one unit anyway, so this is not going to
    435  * accumulate).
    436  */
    437 void
    438 ser_fastint()
    439 {
    440 	/*
    441 	 * We're at RBE-level, which is higher than VBL-level which is used
    442 	 * to periodically transmit contents of this buffer up one layer,
    443 	 * so no spl-raising is necessary.
    444 	 */
    445 	register u_short ints, code;
    446 
    447 	ints = custom.intreqr & INTF_RBF;
    448 	if (ints == 0)
    449 		return;
    450 
    451 	/*
    452 	 * this register contains both data and status bits!
    453 	 */
    454 	code = custom.serdatr;
    455 
    456 	/*
    457 	 * clear interrupt
    458 	 */
    459 	custom.intreq = ints;
    460 
    461 	/*
    462 	 * check for buffer overflow.
    463 	 */
    464 	if (sbcnt == SERIBUF_SIZE) {
    465 		++sbovfl;
    466 		return;
    467 	}
    468 	/*
    469 	 * store in buffer
    470 	 */
    471 	*sbwpt++ = code;
    472 	if (sbwpt == serbuf + SERIBUF_SIZE)
    473 		sbwpt = serbuf;
    474 	++sbcnt;
    475 	if (sbcnt > SERIBUF_SIZE - 20)
    476 		CLRRTS(ciab.pra);	/* drop RTS if buffer almost full */
    477 }
    478 
    479 
    480 void
    481 serintr(unit)
    482 	int unit;
    483 {
    484 	int s1, s2, ovfl;
    485 	struct tty *tp = ser_tty[unit];
    486 
    487 	/*
    488 	 * Make sure we're not interrupted by another
    489 	 * vbl, but allow level5 ints
    490 	 */
    491 	s1 = spltty();
    492 
    493 	/*
    494 	 * pass along any acumulated information
    495 	 */
    496 	while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
    497 		/*
    498 		 * no collision with ser_fastint()
    499 		 */
    500 		sereint(unit, *sbrpt++);
    501 
    502 		ovfl = 0;
    503 		/* lock against ser_fastint() */
    504 		s2 = splser();
    505 		sbcnt--;
    506 		if (sbrpt == serbuf + SERIBUF_SIZE)
    507 			sbrpt = serbuf;
    508 		if (sbovfl != 0) {
    509 			ovfl = sbovfl;
    510 			sbovfl = 0;
    511 		}
    512 		splx(s2);
    513 		if (ovfl != 0)
    514 			log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
    515 			    ovfl);
    516 	}
    517 	s2 = splser();
    518 	if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
    519 		SETRTS(ciab.pra);	/* start accepting data again */
    520 	splx(s2);
    521 	splx(s1);
    522 }
    523 
    524 void
    525 sereint(unit, stat)
    526 	int unit, stat;
    527 {
    528 	struct tty *tp;
    529 	u_char ch;
    530 	int c;
    531 
    532 	tp = ser_tty[unit];
    533 	ch = stat & 0xff;
    534 	c = ch;
    535 
    536 	if ((tp->t_state & TS_ISOPEN) == 0) {
    537 #ifdef KGDB
    538 		/* we don't care about parity errors */
    539 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
    540 			kgdb_connect(0);	/* trap into kgdb */
    541 #endif
    542 		return;
    543 	}
    544 
    545 	/*
    546 	 * Check for break and (if enabled) parity error.
    547 	 */
    548 	if ((stat & 0x1ff) == 0)
    549 		c |= TTY_FE;
    550 	else if ((tp->t_cflag & PARENB) &&
    551 		    (((ch >> 7) + even_parity[ch & 0x7f]
    552 		    + !!(tp->t_cflag & PARODD)) & 1))
    553 			c |= TTY_PE;
    554 
    555 	if (stat & SERDATRF_OVRUN)
    556 		log(LOG_WARNING, "ser0: silo overflow\n");
    557 
    558 	(*linesw[tp->t_line].l_rint)(c, tp);
    559 }
    560 
    561 /*
    562  * This interrupt is periodically invoked in the vertical blank
    563  * interrupt.  It's used to keep track of the modem control lines
    564  * and (new with the fast_int code) to move accumulated data
    565  * up into the tty layer.
    566  */
    567 void
    568 sermint(unit)
    569 	int unit;
    570 {
    571 	struct tty *tp;
    572 	u_char stat, last, istat;
    573 
    574 	tp = ser_tty[unit];
    575 	if (!tp)
    576 		return;
    577 
    578 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
    579 		sbrpt = sbwpt = serbuf;
    580 		return;
    581 	}
    582 	/*
    583 	 * empty buffer
    584 	 */
    585 	serintr(unit);
    586 
    587 	stat = ciab.pra;
    588 	last = last_ciab_pra;
    589 	last_ciab_pra = stat;
    590 
    591 	/*
    592 	 * check whether any interesting signal changed state
    593 	 */
    594 	istat = stat ^ last;
    595 
    596 	if ((istat & CIAB_PRA_CD) &&
    597 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
    598 		if (ISDCD(stat))
    599 			(*linesw[tp->t_line].l_modem)(tp, 1);
    600 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
    601 			CLRDTR(stat);
    602 			CLRRTS(stat);
    603 			ciab.pra = stat;
    604 			last_ciab_pra = stat;
    605 		}
    606 	}
    607 	if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
    608 	    (tp->t_cflag & CRTSCTS)) {
    609 #if 0
    610 		/* the line is up and we want to do rts/cts flow control */
    611 		if (ISCTS(stat)) {
    612 			tp->t_state &= ~TS_TTSTOP;
    613 			ttstart(tp);
    614 			/* cause tbe-int if we were stuck there */
    615 			custom.intreq = INTF_SETCLR | INTF_TBE;
    616 		} else
    617 			tp->t_state |= TS_TTSTOP;
    618 #else
    619 		/* do this on hardware level, not with tty driver */
    620 		if (ISCTS(stat)) {
    621 			tp->t_state &= ~TS_TTSTOP;
    622 			/* cause TBE interrupt */
    623 			custom.intreq = INTF_SETCLR | INTF_TBE;
    624 		}
    625 #endif
    626 	}
    627 }
    628 
    629 int
    630 serioctl(dev, cmd, data, flag, p)
    631 	dev_t dev;
    632 	u_long cmd;
    633 	caddr_t data;
    634 	int flag;
    635 	struct proc *p;
    636 {
    637 	register struct tty *tp;
    638 	register int unit = SERUNIT(dev);
    639 	register int error;
    640 
    641 	tp = ser_tty[unit];
    642 	if (!tp)
    643 		return ENXIO;
    644 
    645 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    646 	if (error >= 0)
    647 		return(error);
    648 
    649 	error = ttioctl(tp, cmd, data, flag, p);
    650 	if (error >= 0)
    651 		return(error);
    652 
    653 	switch (cmd) {
    654 	case TIOCSBRK:
    655 		custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
    656 		break;
    657 
    658 	case TIOCCBRK:
    659 		custom.adkcon = ADKCONF_UARTBRK;
    660 		break;
    661 
    662 	case TIOCSDTR:
    663 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    664 		break;
    665 
    666 	case TIOCCDTR:
    667 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    668 		break;
    669 
    670 	case TIOCMSET:
    671 		(void) sermctl(dev, *(int *) data, DMSET);
    672 		break;
    673 
    674 	case TIOCMBIS:
    675 		(void) sermctl(dev, *(int *) data, DMBIS);
    676 		break;
    677 
    678 	case TIOCMBIC:
    679 		(void) sermctl(dev, *(int *) data, DMBIC);
    680 		break;
    681 
    682 	case TIOCMGET:
    683 		*(int *)data = sermctl(dev, 0, DMGET);
    684 		break;
    685 	case TIOCGFLAGS:
    686 		*(int *)data = SWFLAGS(dev);
    687 		break;
    688 	case TIOCSFLAGS:
    689 		error = suser(p->p_ucred, &p->p_acflag);
    690 		if (error != 0)
    691 			return(EPERM);
    692 
    693 		serswflags = *(int *)data;
    694                 serswflags &= /* only allow valid flags */
    695                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
    696 		break;
    697 	default:
    698 		return(ENOTTY);
    699 	}
    700 
    701 	return(0);
    702 }
    703 
    704 int
    705 serparam(tp, t)
    706 	struct tty *tp;
    707 	struct termios *t;
    708 {
    709 	int cflag, unit, ospeed = 0;
    710 
    711 	cflag = t->c_cflag;
    712 	unit = SERUNIT(tp->t_dev);
    713 
    714 	if (t->c_ospeed > 0) {
    715 		if (t->c_ospeed < 110)
    716 			return(EINVAL);
    717 		ospeed = SERBRD(t->c_ospeed);
    718 	}
    719 
    720 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    721 		return(EINVAL);
    722 
    723 	/*
    724 	 * copy to tty
    725 	 */
    726 	tp->t_ispeed = t->c_ispeed;
    727 	tp->t_ospeed = t->c_ospeed;
    728 	tp->t_cflag = cflag;
    729 
    730 	/*
    731 	 * enable interrupts
    732 	 */
    733 	custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
    734 	last_ciab_pra = ciab.pra;
    735 
    736 	if (t->c_ospeed == 0)
    737 		(void)sermctl(tp->t_dev, 0, DMSET);	/* hang up line */
    738 	else {
    739 		/*
    740 		 * (re)enable DTR
    741 		 * and set baud rate. (8 bit mode)
    742 		 */
    743 		(void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    744 		custom.serper = (0 << 15) | ospeed;
    745 	}
    746 	return(0);
    747 }
    748 
    749 int serhwiflow(tp, flag)
    750         struct tty *tp;
    751         int flag;
    752 {
    753 #if 0
    754 	printf ("serhwiflow %d\n", flag);
    755 #endif
    756         if (flag)
    757 		CLRRTS(ciab.pra);
    758 	else
    759 	        SETRTS(ciab.pra);
    760         return 1;
    761 }
    762 
    763 static void
    764 ser_putchar(tp, c)
    765 	struct tty *tp;
    766 	u_short c;
    767 {
    768 	if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
    769 		c &= 0x7f;
    770 
    771 	/*
    772 	 * handle parity if necessary
    773 	 */
    774 	if (tp->t_cflag & PARENB) {
    775 		if (even_parity[c])
    776 			c |= 0x80;
    777 		if (tp->t_cflag & PARODD)
    778 			c ^= 0x80;
    779 	}
    780 	/*
    781 	 * add stop bit(s)
    782 	 */
    783 	if (tp->t_cflag & CSTOPB)
    784 		c |= 0x300;
    785 	else
    786 		c |= 0x100;
    787 
    788 	custom.serdat = c;
    789 }
    790 
    791 
    792 static u_char ser_outbuf[SEROBUF_SIZE];
    793 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
    794 
    795 void
    796 ser_outintr()
    797 {
    798 	struct tty *tp = ser_tty[0];
    799 	int s;
    800 
    801 	tp = ser_tty[0];
    802 	s = spltty();
    803 
    804 	if (tp == 0)
    805 		goto out;
    806 
    807 	if ((custom.intreqr & INTF_TBE) == 0)
    808 		goto out;
    809 
    810 	/*
    811 	 * clear interrupt
    812 	 */
    813 	custom.intreq = INTF_TBE;
    814 
    815 	if (sob_ptr == sob_end) {
    816 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    817 		if (tp->t_line)
    818 			(*linesw[tp->t_line].l_start)(tp);
    819 		else
    820 			serstart(tp);
    821 		goto out;
    822 	}
    823 
    824 	/*
    825 	 * Do hardware flow control here.  if the CTS line goes down, don't
    826 	 * transmit anything.  That way, we'll be restarted by the periodic
    827 	 * interrupt when CTS comes back up.
    828 	 */
    829 	if (ISCTS(ciab.pra))
    830 		ser_putchar(tp, *sob_ptr++);
    831 	else
    832 		CLRCTS(last_ciab_pra);	/* Remember that CTS is off */
    833 out:
    834 	splx(s);
    835 }
    836 
    837 void
    838 serstart(tp)
    839 	struct tty *tp;
    840 {
    841 	int cc, s, unit, hiwat;
    842 
    843 	hiwat = 0;
    844 
    845 	if ((tp->t_state & TS_ISOPEN) == 0)
    846 		return;
    847 
    848 	unit = SERUNIT(tp->t_dev);
    849 
    850 	s = spltty();
    851 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    852 		goto out;
    853 
    854 	cc = tp->t_outq.c_cc;
    855 	if (cc <= tp->t_lowat) {
    856 		if (tp->t_state & TS_ASLEEP) {
    857 			tp->t_state &= ~TS_ASLEEP;
    858 			wakeup((caddr_t) & tp->t_outq);
    859 		}
    860 		selwakeup(&tp->t_wsel);
    861 	}
    862 	if (cc == 0 || (tp->t_state & TS_BUSY))
    863 		goto out;
    864 
    865 	/*
    866 	 * We only do bulk transfers if using CTSRTS flow control, not for
    867 	 * (probably sloooow) ixon/ixoff devices.
    868 	 */
    869 	if ((tp->t_cflag & CRTSCTS) == 0)
    870 		cc = 1;
    871 
    872 	/*
    873 	 * Limit the amount of output we do in one burst
    874 	 * to prevent hogging the CPU.
    875 	 */
    876 	if (cc > SEROBUF_SIZE) {
    877 		hiwat++;
    878 		cc = SEROBUF_SIZE;
    879 	}
    880 	cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
    881 	if (cc > 0) {
    882 		tp->t_state |= TS_BUSY;
    883 
    884 		sob_ptr = ser_outbuf;
    885 		sob_end = ser_outbuf + cc;
    886 
    887 		/*
    888 		 * Get first character out, then have TBE-interrupts blow out
    889 		 * further characters, until buffer is empty, and TS_BUSY gets
    890 		 * cleared.
    891 		 */
    892 		ser_putchar(tp, *sob_ptr++);
    893 	}
    894 out:
    895 	splx(s);
    896 }
    897 
    898 /*
    899  * Stop output on a line.
    900  */
    901 /*ARGSUSED*/
    902 void
    903 serstop(tp, flag)
    904 	struct tty *tp;
    905 	int flag;
    906 {
    907 	int s;
    908 
    909 	s = spltty();
    910 	if (tp->t_state & TS_BUSY) {
    911 		if ((tp->t_state & TS_TTSTOP) == 0)
    912 			tp->t_state |= TS_FLUSH;
    913 	}
    914 	splx(s);
    915 }
    916 
    917 int
    918 sermctl(dev, bits, how)
    919 	dev_t dev;
    920 	int bits, how;
    921 {
    922 	int unit, s;
    923 	u_char ub = 0;
    924 
    925 	unit = SERUNIT(dev);
    926 
    927 	/*
    928 	 * convert TIOCM* mask into CIA mask
    929 	 * which is active low
    930 	 */
    931 	if (how != DMGET) {
    932 		ub = 0;
    933 		if (bits & TIOCM_DTR)
    934 			ub |= CIAB_PRA_DTR;
    935 		if (bits & TIOCM_RTS)
    936 			ub |= CIAB_PRA_RTS;
    937 		if (bits & TIOCM_CTS)
    938 			ub |= CIAB_PRA_CTS;
    939 		if (bits & TIOCM_CD)
    940 			ub |= CIAB_PRA_CD;
    941 		if (bits & TIOCM_RI)
    942 			ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    943 		if (bits & TIOCM_DSR)
    944 			ub |= CIAB_PRA_DSR;
    945 	}
    946 	s = spltty();
    947 	switch (how) {
    948 	case DMSET:
    949 		/* invert and set */
    950 		ciab.pra = ~ub;
    951 		break;
    952 
    953 	case DMBIC:
    954 		ciab.pra |= ub;
    955 		ub = ~ciab.pra;
    956 		break;
    957 
    958 	case DMBIS:
    959 		ciab.pra &= ~ub;
    960 		ub = ~ciab.pra;
    961 		break;
    962 
    963 	case DMGET:
    964 		ub = ~ciab.pra;
    965 		break;
    966 	}
    967 	(void)splx(s);
    968 
    969 	bits = 0;
    970 	if (ub & CIAB_PRA_DTR)
    971 		bits |= TIOCM_DTR;
    972 	if (ub & CIAB_PRA_RTS)
    973 		bits |= TIOCM_RTS;
    974 	if (ub & CIAB_PRA_CTS)
    975 		bits |= TIOCM_CTS;
    976 	if (ub & CIAB_PRA_CD)
    977 		bits |= TIOCM_CD;
    978 	if (ub & CIAB_PRA_SEL)
    979 		bits |= TIOCM_RI;
    980 	if (ub & CIAB_PRA_DSR)
    981 		bits |= TIOCM_DSR;
    982 
    983 	return(bits);
    984 }
    985 
    986 /*
    987  * Following are all routines needed for SER to act as console
    988  */
    989 void
    990 sercnprobe(cp)
    991 	struct consdev *cp;
    992 {
    993 	int unit = CONUNIT;
    994 
    995 	/* locate the major number */
    996 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
    997 		if (cdevsw[sermajor].d_open == (void *)seropen)
    998 			break;
    999 
   1000 
   1001 	unit = CONUNIT;			/* XXX: ick */
   1002 
   1003 	/*
   1004 	 * initialize required fields
   1005 	 */
   1006 	cp->cn_dev = makedev(sermajor, unit);
   1007 	if (serconsole == unit)
   1008 		cp->cn_pri = CN_REMOTE;
   1009 	else
   1010 		cp->cn_pri = CN_NORMAL;
   1011 #ifdef KGDB
   1012 	if (major(kgdb_dev) == 1)	/* XXX */
   1013 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
   1014 #endif
   1015 }
   1016 
   1017 void
   1018 sercninit(cp)
   1019 	struct consdev *cp;
   1020 {
   1021 	int unit;
   1022 
   1023 	unit = SERUNIT(cp->cn_dev);
   1024 
   1025 	serinit(unit, serdefaultrate);
   1026 	serconsole = unit;
   1027 	serconsinit = 1;
   1028 }
   1029 
   1030 void
   1031 serinit(unit, rate)
   1032 	int unit, rate;
   1033 {
   1034 	int s;
   1035 
   1036 	s = splser();
   1037 	/*
   1038 	 * might want to fiddle with the CIA later ???
   1039 	 */
   1040 	custom.serper = (rate>=110 ? SERBRD(rate) : 0);
   1041 	splx(s);
   1042 }
   1043 
   1044 int
   1045 sercngetc(dev)
   1046 	dev_t dev;
   1047 {
   1048 	u_short stat;
   1049 	int c, s;
   1050 
   1051 	s = splser();
   1052 	/*
   1053 	 * poll
   1054 	 */
   1055 	while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
   1056 		;
   1057 	c = stat & 0xff;
   1058 	/*
   1059 	 * clear interrupt
   1060 	 */
   1061 	custom.intreq = INTF_RBF;
   1062 	splx(s);
   1063 	return(c);
   1064 }
   1065 
   1066 /*
   1067  * Console kernel output character routine.
   1068  */
   1069 void
   1070 sercnputc(dev, c)
   1071 	dev_t dev;
   1072 	int c;
   1073 {
   1074 	register int timo;
   1075 	int s;
   1076 
   1077 	s = splhigh();
   1078 
   1079 	if (serconsinit == 0) {
   1080 		(void)serinit(SERUNIT(dev), serdefaultrate);
   1081 		serconsinit = 1;
   1082 	}
   1083 
   1084 	/*
   1085 	 * wait for any pending transmission to finish
   1086 	 */
   1087 	timo = 50000;
   1088 	while (!(custom.serdatr & SERDATRF_TBE) && --timo);
   1089 
   1090 	/*
   1091 	 * transmit char.
   1092 	 */
   1093 	custom.serdat = (c & 0xff) | 0x100;
   1094 
   1095 	/*
   1096 	 * wait for this transmission to complete
   1097 	 */
   1098 	timo = 1500000;
   1099 	while (!(custom.serdatr & SERDATRF_TBE) && --timo)
   1100 		;
   1101 
   1102 	/*
   1103 	 * Wait for the device (my vt100..) to process the data, since we
   1104 	 * don't do flow-control with cnputc
   1105 	 */
   1106 	for (timo = 0; timo < 30000; timo++)
   1107 		;
   1108 
   1109 	/*
   1110 	 * clear any interrupts generated by this transmission
   1111 	 */
   1112 	custom.intreq = INTF_TBE;
   1113 	splx(s);
   1114 }
   1115 
   1116 void
   1117 sercnpollc(dev, on)
   1118 	dev_t dev;
   1119 	int on;
   1120 {
   1121 }
   1122 #endif
   1123