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