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