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