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