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