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