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