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