Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.21
      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.21 1994/08/31 02:13:01 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 		++sbovfl;
    431 		return;
    432 	}
    433 	/*
    434 	 * store in buffer
    435 	 */
    436 	*sbwpt++ = code;
    437 	if (sbwpt == serbuf + SERIBUF_SIZE)
    438 		sbwpt = serbuf;
    439 }
    440 
    441 
    442 int
    443 serintr(unit)
    444 	int unit;
    445 {
    446 	int s1, s2, ovfl;
    447 
    448 	/*
    449 	 * Make sure we're not interrupted by another
    450 	 * vbl, but allow level5 ints
    451 	 */
    452 	s1 = spltty();
    453 
    454 	/*
    455 	 * pass along any acumulated information
    456 	 */
    457 	while (sbrpt != sbwpt) {
    458 		/*
    459 		 * no collision with ser_fastint()
    460 		 */
    461 		sereint(unit, *sbrpt);
    462 
    463 		ovfl = 0;
    464 		/* lock against ser_fastint() */
    465 		s2 = spl5();
    466 		sbrpt++;
    467 		if (sbrpt == serbuf + SERIBUF_SIZE)
    468 			sbrpt = serbuf;
    469 		if (sbovfl != 0) {
    470 			ovfl = sbovfl;
    471 			sbovfl = 0;
    472 		}
    473 		splx(s2);
    474 		if (ovfl != 0)
    475 			log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
    476 			    ovfl);
    477 	}
    478 	splx(s1);
    479 }
    480 
    481 int
    482 sereint(unit, stat)
    483 	int unit, stat;
    484 {
    485 	struct tty *tp;
    486 	u_char ch;
    487 	int c;
    488 
    489 	tp = ser_tty[unit];
    490 	ch = stat & 0xff;
    491 	c = ch;
    492 
    493 	if ((tp->t_state & TS_ISOPEN) == 0) {
    494 #ifdef KGDB
    495 		/* we don't care about parity errors */
    496 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
    497 			kgdb_connect(0);	/* trap into kgdb */
    498 #endif
    499 		return;
    500 	}
    501 
    502 	/*
    503 	 * Check for break and (if enabled) parity error.
    504 	 */
    505 	if ((stat & 0x1ff) == 0)
    506 		c |= TTY_FE;
    507 	else if ((tp->t_cflag & PARENB) &&
    508 		    (((ch >> 7) + even_parity[ch & 0x7f]
    509 		    + !!(tp->t_cflag & PARODD)) & 1))
    510 			c |= TTY_PE;
    511 
    512 	if (stat & SERDATRF_OVRUN)
    513 		log(LOG_WARNING, "ser0: silo overflow\n");
    514 
    515 	(*linesw[tp->t_line].l_rint)(c, tp);
    516 }
    517 
    518 /*
    519  * This interrupt is periodically invoked in the vertical blank
    520  * interrupt.  It's used to keep track of the modem control lines
    521  * and (new with the fast_int code) to move accumulated data
    522  * up into the tty layer.
    523  */
    524 void
    525 sermint(unit)
    526 	int unit;
    527 {
    528 	struct tty *tp;
    529 	u_char stat, last, istat;
    530 
    531 	tp = ser_tty[unit];
    532 	if (!tp)
    533 		return;
    534 
    535 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
    536 		sbrpt = sbwpt = serbuf;
    537 		return;
    538 	}
    539 	/*
    540 	 * empty buffer
    541 	 */
    542 	serintr(unit);
    543 
    544 	stat = ciab.pra;
    545 	last = last_ciab_pra;
    546 	last_ciab_pra = stat;
    547 
    548 	/*
    549 	 * check whether any interesting signal changed state
    550 	 */
    551 	istat = stat ^ last;
    552 
    553 	if ((istat & CIAB_PRA_CD) &&
    554 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
    555 		if (ISDCD(stat))
    556 			(*linesw[tp->t_line].l_modem)(tp, 1);
    557 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
    558 			CLRDTR(stat);
    559 			CLRRTS(stat);
    560 			ciab.pra = stat;
    561 			last_ciab_pra = stat;
    562 		}
    563 	}
    564 	if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
    565 	    (tp->t_cflag & CRTSCTS)) {
    566 #if 0
    567 		/* the line is up and we want to do rts/cts flow control */
    568 		if (ISCTS(stat)) {
    569 			tp->t_state &= ~TS_TTSTOP;
    570 			ttstart(tp);
    571 			/* cause tbe-int if we were stuck there */
    572 			custom.intreq = INTF_SETCLR | INTF_TBE;
    573 		} else
    574 			tp->t_state |= TS_TTSTOP;
    575 #else
    576 		/* do this on hardware level, not with tty driver */
    577 		if (ISCTS(stat)) {
    578 			tp->t_state &= ~TS_TTSTOP;
    579 			/* cause TBE interrupt */
    580 			custom.intreq = INTF_SETCLR | INTF_TBE;
    581 		}
    582 #endif
    583 	}
    584 }
    585 
    586 int
    587 serioctl(dev, cmd, data, flag, p)
    588 	dev_t	dev;
    589 	caddr_t data;
    590 	struct proc *p;
    591 {
    592 	register struct tty *tp;
    593 	register int unit = SERUNIT(dev);
    594 	register int error;
    595 
    596 	tp = ser_tty[unit];
    597 	if (!tp)
    598 		return ENXIO;
    599 
    600 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    601 	if (error >= 0)
    602 		return(error);
    603 
    604 	error = ttioctl(tp, cmd, data, flag, p);
    605 	if (error >= 0)
    606 		return(error);
    607 
    608 	switch (cmd) {
    609 	case TIOCSBRK:
    610 		custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
    611 		break;
    612 
    613 	case TIOCCBRK:
    614 		custom.adkcon = ADKCONF_UARTBRK;
    615 		break;
    616 
    617 	case TIOCSDTR:
    618 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    619 		break;
    620 
    621 	case TIOCCDTR:
    622 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    623 		break;
    624 
    625 	case TIOCMSET:
    626 		(void) sermctl(dev, *(int *) data, DMSET);
    627 		break;
    628 
    629 	case TIOCMBIS:
    630 		(void) sermctl(dev, *(int *) data, DMBIS);
    631 		break;
    632 
    633 	case TIOCMBIC:
    634 		(void) sermctl(dev, *(int *) data, DMBIC);
    635 		break;
    636 
    637 	case TIOCMGET:
    638 		*(int *)data = sermctl(dev, 0, DMGET);
    639 		break;
    640 	case TIOCGFLAGS:
    641 		*(int *)data = SWFLAGS(dev);
    642 		break;
    643 	case TIOCSFLAGS:
    644 		error = suser(p->p_ucred, &p->p_acflag);
    645 		if (error != 0)
    646 			return(EPERM);
    647 
    648 		serswflags = *(int *)data;
    649                 serswflags &= /* only allow valid flags */
    650                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
    651 		break;
    652 	default:
    653 		return(ENOTTY);
    654 	}
    655 
    656 	return(0);
    657 }
    658 
    659 int
    660 serparam(tp, t)
    661 	struct tty *tp;
    662 	struct termios *t;
    663 {
    664 	int cfcr, cflag, unit, ospeed;
    665 
    666 	cflag = t->c_cflag;
    667 	unit = SERUNIT(tp->t_dev);
    668 	ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
    669 
    670 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    671 		return(EINVAL);
    672 
    673 	/*
    674 	 * copy to tty
    675 	 */
    676 	tp->t_ispeed = t->c_ispeed;
    677 	tp->t_ospeed = t->c_ospeed;
    678 	tp->t_cflag = cflag;
    679 
    680 	/*
    681 	 * enable interrupts
    682 	 */
    683 	custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
    684 	last_ciab_pra = ciab.pra;
    685 
    686 	if (ospeed == 0)
    687 		(void)sermctl(tp->t_dev, 0, DMSET);	/* hang up line */
    688 	else {
    689 		/*
    690 		 * (re)enable DTR
    691 		 * and set baud rate. (8 bit mode)
    692 		 */
    693 		(void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    694 		custom.serper = (0 << 15) | ospeed;
    695 	}
    696 	return(0);
    697 }
    698 
    699 
    700 static void
    701 ser_putchar(tp, c)
    702 	struct tty *tp;
    703 	u_short c;
    704 {
    705 	if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
    706 		c &= 0x7f;
    707 
    708 	/*
    709 	 * handle parity if necessary
    710 	 */
    711 	if (tp->t_cflag & PARENB) {
    712 		if (even_parity[c])
    713 			c |= 0x80;
    714 		if (tp->t_cflag & PARODD)
    715 			c ^= 0x80;
    716 	}
    717 	/*
    718 	 * add stop bit(s)
    719 	 */
    720 	if (tp->t_cflag & CSTOPB)
    721 		c |= 0x300;
    722 	else
    723 		c |= 0x100;
    724 
    725 	custom.serdat = c;
    726 }
    727 
    728 
    729 static u_char ser_outbuf[SEROBUF_SIZE];
    730 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
    731 
    732 void
    733 ser_outintr()
    734 {
    735 	struct tty *tp = ser_tty[0];
    736 	u_short c;
    737 	int s;
    738 
    739 	tp = ser_tty[0];
    740 	s = spltty();
    741 
    742 	if (tp == 0)
    743 		goto out;
    744 
    745 	if ((custom.intreqr & INTF_TBE) == 0)
    746 		goto out;
    747 
    748 	/*
    749 	 * clear interrupt
    750 	 */
    751 	custom.intreq = INTF_TBE;
    752 
    753 	if (sob_ptr == sob_end) {
    754 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    755 		if (tp->t_line)
    756 			(*linesw[tp->t_line].l_start)(tp);
    757 		else
    758 			serstart(tp);
    759 		goto out;
    760 	}
    761 
    762 	/*
    763 	 * Do hardware flow control here.  if the CTS line goes down, don't
    764 	 * transmit anything.  That way, we'll be restarted by the periodic
    765 	 * interrupt when CTS comes back up.
    766 	 */
    767 	if (ISCTS(ciab.pra))
    768 		ser_putchar(tp, *sob_ptr++);
    769 out:
    770 	splx(s);
    771 }
    772 
    773 int
    774 serstart(tp)
    775 	struct tty *tp;
    776 {
    777 	int cc, s, unit, hiwat;
    778 
    779 	hiwat = 0;
    780 
    781 	if ((tp->t_state & TS_ISOPEN) == 0)
    782 		return;
    783 
    784 	unit = SERUNIT(tp->t_dev);
    785 
    786 	s = spltty();
    787 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    788 		goto out;
    789 
    790 	cc = tp->t_outq.c_cc;
    791 	if (cc <= tp->t_lowat) {
    792 		if (tp->t_state & TS_ASLEEP) {
    793 			tp->t_state &= ~TS_ASLEEP;
    794 			wakeup((caddr_t) & tp->t_outq);
    795 		}
    796 		selwakeup(&tp->t_wsel);
    797 	}
    798 	if (cc == 0 || (tp->t_state & TS_BUSY))
    799 		goto out;
    800 
    801 	/*
    802 	 * We only do bulk transfers if using CTSRTS flow control, not for
    803 	 * (probably sloooow) ixon/ixoff devices.
    804 	 */
    805 	if ((tp->t_cflag & CRTSCTS) == 0)
    806 		cc = 1;
    807 
    808 	/*
    809 	 * Limit the amount of output we do in one burst
    810 	 * to prevent hogging the CPU.
    811 	 */
    812 	if (cc > SEROBUF_SIZE) {
    813 		hiwat++;
    814 		cc = SEROBUF_SIZE;
    815 	}
    816 	cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
    817 	if (cc > 0) {
    818 		tp->t_state |= TS_BUSY;
    819 
    820 		sob_ptr = ser_outbuf;
    821 		sob_end = ser_outbuf + cc;
    822 
    823 		/*
    824 		 * Get first character out, then have TBE-interrupts blow out
    825 		 * further characters, until buffer is empty, and TS_BUSY gets
    826 		 * cleared.
    827 		 */
    828 		ser_putchar(tp, *sob_ptr++);
    829 	}
    830 out:
    831 	splx(s);
    832 }
    833 
    834 /*
    835  * Stop output on a line.
    836  */
    837 /*ARGSUSED*/
    838 int
    839 serstop(tp, flag)
    840 	struct tty *tp;
    841 {
    842 	int s;
    843 
    844 	s = spltty();
    845 	if (tp->t_state & TS_BUSY) {
    846 		if ((tp->t_state & TS_TTSTOP) == 0)
    847 			tp->t_state |= TS_FLUSH;
    848 	}
    849 	splx(s);
    850 }
    851 
    852 int
    853 sermctl(dev, bits, how)
    854 	dev_t dev;
    855 	int bits, how;
    856 {
    857 	int unit, s;
    858 	u_char ub;
    859 
    860 	unit = SERUNIT(dev);
    861 
    862 	/*
    863 	 * convert TIOCM* mask into CIA mask
    864 	 * which is active low
    865 	 */
    866 	if (how != DMGET) {
    867 		ub = 0;
    868 		if (bits & TIOCM_DTR)
    869 			ub |= CIAB_PRA_DTR;
    870 		if (bits & TIOCM_RTS)
    871 			ub |= CIAB_PRA_RTS;
    872 		if (bits & TIOCM_CTS)
    873 			ub |= CIAB_PRA_CTS;
    874 		if (bits & TIOCM_CD)
    875 			ub |= CIAB_PRA_CD;
    876 		if (bits & TIOCM_RI)
    877 			ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    878 		if (bits & TIOCM_DSR)
    879 			ub |= CIAB_PRA_DSR;
    880 	}
    881 	s = spltty();
    882 	switch (how) {
    883 	case DMSET:
    884 		/* invert and set */
    885 		ciab.pra = ~ub;
    886 		break;
    887 
    888 	case DMBIC:
    889 		ciab.pra |= ub;
    890 		ub = ~ciab.pra;
    891 		break;
    892 
    893 	case DMBIS:
    894 		ciab.pra &= ~ub;
    895 		ub = ~ciab.pra;
    896 		break;
    897 
    898 	case DMGET:
    899 		ub = ~ciab.pra;
    900 		break;
    901 	}
    902 	(void)splx(s);
    903 
    904 	bits = 0;
    905 	if (ub & CIAB_PRA_DTR)
    906 		bits |= TIOCM_DTR;
    907 	if (ub & CIAB_PRA_RTS)
    908 		bits |= TIOCM_RTS;
    909 	if (ub & CIAB_PRA_CTS)
    910 		bits |= TIOCM_CTS;
    911 	if (ub & CIAB_PRA_CD)
    912 		bits |= TIOCM_CD;
    913 	if (ub & CIAB_PRA_SEL)
    914 		bits |= TIOCM_RI;
    915 	if (ub & CIAB_PRA_DSR)
    916 		bits |= TIOCM_DSR;
    917 
    918 	return(bits);
    919 }
    920 
    921 /*
    922  * Following are all routines needed for SER to act as console
    923  */
    924 int
    925 sercnprobe(cp)
    926 	struct consdev *cp;
    927 {
    928 	int unit = CONUNIT;
    929 
    930 	/* locate the major number */
    931 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
    932 		if (cdevsw[sermajor].d_open == (void *)seropen)
    933 			break;
    934 
    935 
    936 	unit = CONUNIT;			/* XXX: ick */
    937 
    938 	/*
    939 	 * initialize required fields
    940 	 */
    941 	cp->cn_dev = makedev(sermajor, unit);
    942 	if (serconsole == unit)
    943 		cp->cn_pri = CN_REMOTE;
    944 	else
    945 		cp->cn_pri = CN_NORMAL;
    946 #ifdef KGDB
    947 	if (major(kgdb_dev) == 1)	/* XXX */
    948 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
    949 #endif
    950 }
    951 
    952 sercninit(cp)
    953 	struct consdev *cp;
    954 {
    955 	int unit;
    956 
    957 	unit = SERUNIT(cp->cn_dev);
    958 
    959 	serinit(unit, serdefaultrate);
    960 	serconsole = unit;
    961 	serconsinit = 1;
    962 }
    963 
    964 serinit(unit, rate)
    965 	int unit, rate;
    966 {
    967 	int s;
    968 
    969 	s = splhigh();
    970 	/*
    971 	 * might want to fiddle with the CIA later ???
    972 	 */
    973 	custom.serper = ttspeedtab(rate, serspeedtab);
    974 	splx(s);
    975 }
    976 
    977 sercngetc(dev)
    978 {
    979 	u_short stat;
    980 	int c, s;
    981 
    982 	s = splhigh();
    983 	/*
    984 	 * poll
    985 	 */
    986 	while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
    987 		;
    988 	c = stat & 0xff;
    989 	/*
    990 	 * clear interrupt
    991 	 */
    992 	custom.intreq = INTF_RBF;
    993 	splx(s);
    994 	return(c);
    995 }
    996 
    997 /*
    998  * Console kernel output character routine.
    999  */
   1000 sercnputc(dev, c)
   1001 	dev_t dev;
   1002 	int c;
   1003 {
   1004 	register int timo;
   1005 	short stat;
   1006 	int s;
   1007 
   1008 	s = splhigh();
   1009 
   1010 	if (serconsinit == 0) {
   1011 		(void)serinit(SERUNIT(dev), serdefaultrate);
   1012 		serconsinit = 1;
   1013 	}
   1014 
   1015 	/*
   1016 	 * wait for any pending transmission to finish
   1017 	 */
   1018 	timo = 50000;
   1019 	while (!(custom.serdatr & SERDATRF_TBE) && --timo);
   1020 
   1021 	/*
   1022 	 * transmit char.
   1023 	 */
   1024 	custom.serdat = (c & 0xff) | 0x100;
   1025 
   1026 	/*
   1027 	 * wait for this transmission to complete
   1028 	 */
   1029 	timo = 1500000;
   1030 	while (!(custom.serdatr & SERDATRF_TBE) && --timo)
   1031 		;
   1032 
   1033 	/*
   1034 	 * Wait for the device (my vt100..) to process the data, since we
   1035 	 * don't do flow-control with cnputc
   1036 	 */
   1037 	for (timo = 0; timo < 30000; timo++)
   1038 		;
   1039 
   1040 	/*
   1041 	 * clear any interrupts generated by this transmission
   1042 	 */
   1043 	custom.intreq = INTF_TBE;
   1044 	splx(s);
   1045 }
   1046 #endif
   1047