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