Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.44
      1 /*	$NetBSD: ser.c,v 1.44 1998/04/11 19:30:56 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 		 * fetch current modem control status
    296 		 */
    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 | TIOCM_RTS, 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 	register u_short ints, code;
    472 
    473 	/* XXX should this ever happen? */
    474 	ints = custom.intreqr & INTF_RBF;
    475 	if (ints == 0)
    476 		return;
    477 
    478 	/*
    479 	 * this register contains both data and status bits!
    480 	 */
    481 	code = custom.serdatr;
    482 
    483 	/*
    484 	 * clear interrupt
    485 	 */
    486 	custom.intreq = INTF_RBF;
    487 
    488 	/*
    489 	 * check for buffer overflow.
    490 	 */
    491 	if (sbcnt == SERIBUF_SIZE) {
    492 		++sbovfl;
    493 		return;
    494 	}
    495 	/*
    496 	 * store in buffer
    497 	 */
    498 	*sbwpt++ = code;
    499 	if (sbwpt == serbuf + SERIBUF_SIZE)
    500 		sbwpt = serbuf;
    501 	++sbcnt;
    502 	if (sbcnt > SERIBUF_SIZE - 20)
    503 		CLRRTS(ciab.pra);	/* drop RTS if buffer almost full */
    504 }
    505 
    506 
    507 void
    508 serintr()
    509 {
    510 	int s1, s2, ovfl;
    511 	struct tty *tp = ser_tty;
    512 
    513 	/*
    514 	 * Make sure we're not interrupted by another
    515 	 * vbl, but allow level5 ints
    516 	 */
    517 	s1 = spltty();
    518 
    519 	/*
    520 	 * pass along any acumulated information
    521 	 */
    522 	while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
    523 		/*
    524 		 * no collision with ser_fastint()
    525 		 */
    526 		sereint(*sbrpt++);
    527 
    528 		ovfl = 0;
    529 		/* lock against ser_fastint() */
    530 		s2 = splser();
    531 		sbcnt--;
    532 		if (sbrpt == serbuf + SERIBUF_SIZE)
    533 			sbrpt = serbuf;
    534 		if (sbovfl != 0) {
    535 			ovfl = sbovfl;
    536 			sbovfl = 0;
    537 		}
    538 		splx(s2);
    539 		if (ovfl != 0)
    540 			log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
    541 			    ovfl);
    542 	}
    543 	s2 = splser();
    544 	if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
    545 		SETRTS(ciab.pra);	/* start accepting data again */
    546 	splx(s2);
    547 	splx(s1);
    548 }
    549 
    550 void
    551 sereint(stat)
    552 	int stat;
    553 {
    554 	struct tty *tp;
    555 	u_char ch;
    556 	int c;
    557 
    558 	tp = ser_tty;
    559 	ch = stat & 0xff;
    560 	c = ch;
    561 
    562 	if ((tp->t_state & TS_ISOPEN) == 0) {
    563 #ifdef KGDB
    564 		/* we don't care about parity errors */
    565 		if (kgdb_dev == makedev(sermajor, 0) && c == FRAME_END)
    566 			kgdb_connect(0);	/* trap into kgdb */
    567 #endif
    568 		return;
    569 	}
    570 
    571 	/*
    572 	 * Check for break and (if enabled) parity error.
    573 	 */
    574 	if ((stat & 0x1ff) == 0)
    575 		c |= TTY_FE;
    576 	else if ((tp->t_cflag & PARENB) &&
    577 		    (((ch >> 7) + even_parity[ch & 0x7f]
    578 		    + !!(tp->t_cflag & PARODD)) & 1))
    579 			c |= TTY_PE;
    580 
    581 	if (stat & SERDATRF_OVRUN)
    582 		log(LOG_WARNING, "ser0: silo overflow\n");
    583 
    584 	(*linesw[tp->t_line].l_rint)(c, tp);
    585 }
    586 
    587 /*
    588  * This interrupt is periodically invoked in the vertical blank
    589  * interrupt.  It's used to keep track of the modem control lines
    590  * and (new with the fast_int code) to move accumulated data
    591  * up into the tty layer.
    592  */
    593 void
    594 sermint(unit)
    595 	int unit;
    596 {
    597 	struct tty *tp;
    598 	u_char stat, last, istat;
    599 
    600 	tp = ser_tty;
    601 	if (!tp)
    602 		return;
    603 
    604 	/*
    605 	if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) {
    606 		sbrpt = sbwpt = serbuf;
    607 		return;
    608 	}
    609 	*/
    610 	/*
    611 	 * empty buffer
    612 	 */
    613 	serintr();
    614 
    615 	stat = ciab.pra;
    616 	last = last_ciab_pra;
    617 	last_ciab_pra = stat;
    618 
    619 	/*
    620 	 * check whether any interesting signal changed state
    621 	 */
    622 	istat = stat ^ last;
    623 
    624 	if (istat & serdcd) {
    625 		(*linesw[tp->t_line].l_modem)(tp, ISDCD(stat));
    626 	}
    627 
    628 	if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
    629 	    (tp->t_cflag & CRTSCTS)) {
    630 #if 0
    631 		/* the line is up and we want to do rts/cts flow control */
    632 		if (ISCTS(stat)) {
    633 			tp->t_state &= ~TS_TTSTOP;
    634 			ttstart(tp);
    635 			/* cause tbe-int if we were stuck there */
    636 			custom.intreq = INTF_SETCLR | INTF_TBE;
    637 		} else
    638 			tp->t_state |= TS_TTSTOP;
    639 #else
    640 		/* do this on hardware level, not with tty driver */
    641 		if (ISCTS(stat)) {
    642 			tp->t_state &= ~TS_TTSTOP;
    643 			/* cause TBE interrupt */
    644 			custom.intreq = INTF_SETCLR | INTF_TBE;
    645 		}
    646 #endif
    647 	}
    648 }
    649 
    650 int
    651 serioctl(dev, cmd, data, flag, p)
    652 	dev_t dev;
    653 	u_long cmd;
    654 	caddr_t data;
    655 	int flag;
    656 	struct proc *p;
    657 {
    658 	register struct tty *tp;
    659 	register int error;
    660 
    661 	tp = ser_tty;
    662 	if (!tp)
    663 		return ENXIO;
    664 
    665 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    666 	if (error >= 0)
    667 		return(error);
    668 
    669 	error = ttioctl(tp, cmd, data, flag, p);
    670 	if (error >= 0)
    671 		return(error);
    672 
    673 	switch (cmd) {
    674 	case TIOCSBRK:
    675 		custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
    676 		break;
    677 
    678 	case TIOCCBRK:
    679 		custom.adkcon = ADKCONF_UARTBRK;
    680 		break;
    681 
    682 	case TIOCSDTR:
    683 		(void) sermctl(dev, TIOCM_DTR, DMBIS);
    684 		break;
    685 
    686 	case TIOCCDTR:
    687 		(void) sermctl(dev, TIOCM_DTR, DMBIC);
    688 		break;
    689 
    690 	case TIOCMSET:
    691 		(void) sermctl(dev, *(int *) data, DMSET);
    692 		break;
    693 
    694 	case TIOCMBIS:
    695 		(void) sermctl(dev, *(int *) data, DMBIS);
    696 		break;
    697 
    698 	case TIOCMBIC:
    699 		(void) sermctl(dev, *(int *) data, DMBIC);
    700 		break;
    701 
    702 	case TIOCMGET:
    703 		*(int *)data = sermctl(dev, 0, DMGET);
    704 		break;
    705 	case TIOCGFLAGS:
    706 		*(int *)data = serswflags;
    707 		break;
    708 	case TIOCSFLAGS:
    709 		error = suser(p->p_ucred, &p->p_acflag);
    710 		if (error != 0)
    711 			return(EPERM);
    712 
    713 		serswflags = *(int *)data;
    714                 serswflags &= /* only allow valid flags */
    715                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
    716 		break;
    717 	default:
    718 		return(ENOTTY);
    719 	}
    720 
    721 	return(0);
    722 }
    723 
    724 int
    725 serparam(tp, t)
    726 	struct tty *tp;
    727 	struct termios *t;
    728 {
    729 	int cflag, ospeed = 0;
    730 
    731 	if (t->c_ospeed > 0) {
    732 		if (t->c_ospeed < 110)
    733 			return(EINVAL);
    734 		ospeed = SERBRD(t->c_ospeed);
    735 	}
    736 
    737 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    738 		return(EINVAL);
    739 
    740 	/* XXX missing here: console test */
    741 	if (serswflags & TIOCFLAG_SOFTCAR) {
    742 		t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL;
    743 	}
    744 
    745 	/* if no changes, dont do anything. com.c explains why. */
    746 	if (tp->t_ospeed == t->c_ospeed &&
    747 	    tp->t_cflag == t->c_cflag)
    748 		return (0);
    749 
    750 	cflag = t->c_cflag;
    751 
    752 	if (cflag & (CLOCAL | MDMBUF))
    753 		serdcd = 0;
    754 	else
    755 		serdcd = CIAB_PRA_CD;
    756 
    757 	/* TODO: support multiple flow control protocols like com.c */
    758 
    759 	/*
    760 	 * copy to tty
    761 	 */
    762 	tp->t_ispeed = t->c_ispeed;
    763 	tp->t_ospeed = t->c_ospeed;
    764 	tp->t_cflag = cflag;
    765 	ser_open_speed = tp->t_ispeed;
    766 
    767 	/*
    768 	 * enable interrupts
    769 	 */
    770 	custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
    771 	last_ciab_pra = ciab.pra;
    772 
    773 	if (t->c_ospeed == 0)
    774 		(void)sermctl(tp->t_dev, 0, DMSET);	/* hang up line */
    775 	else {
    776 		/*
    777 		 * (re)enable DTR
    778 		 * and set baud rate. (8 bit mode)
    779 		 */
    780 		(void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    781 		custom.serper = (0 << 15) | ospeed;
    782 	}
    783 	return(0);
    784 }
    785 
    786 int serhwiflow(tp, flag)
    787         struct tty *tp;
    788         int flag;
    789 {
    790 #if 0
    791 	printf ("serhwiflow %d\n", flag);
    792 #endif
    793         if (flag)
    794 		CLRRTS(ciab.pra);
    795 	else
    796 	        SETRTS(ciab.pra);
    797         return 1;
    798 }
    799 
    800 static void
    801 ser_putchar(tp, c)
    802 	struct tty *tp;
    803 	u_short c;
    804 {
    805 	if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
    806 		c &= 0x7f;
    807 
    808 	/*
    809 	 * handle parity if necessary
    810 	 */
    811 	if (tp->t_cflag & PARENB) {
    812 		if (even_parity[c])
    813 			c |= 0x80;
    814 		if (tp->t_cflag & PARODD)
    815 			c ^= 0x80;
    816 	}
    817 	/*
    818 	 * add stop bit(s)
    819 	 */
    820 	if (tp->t_cflag & CSTOPB)
    821 		c |= 0x300;
    822 	else
    823 		c |= 0x100;
    824 
    825 	custom.serdat = c;
    826 }
    827 
    828 
    829 static u_char ser_outbuf[SEROBUF_SIZE];
    830 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
    831 
    832 void
    833 ser_outintr()
    834 {
    835 	struct tty *tp;
    836 	int s;
    837 
    838 	tp = ser_tty;
    839 	s = spltty();
    840 
    841 	if (tp == 0)
    842 		goto out;
    843 
    844 	if ((custom.intreqr & INTF_TBE) == 0)
    845 		goto out;
    846 
    847 	/*
    848 	 * clear interrupt
    849 	 */
    850 	custom.intreq = INTF_TBE;
    851 
    852 	if (sob_ptr == sob_end) {
    853 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    854 		if (tp->t_line)
    855 			(*linesw[tp->t_line].l_start)(tp);
    856 		else
    857 			serstart(tp);
    858 		goto out;
    859 	}
    860 
    861 	/*
    862 	 * Do hardware flow control here.  if the CTS line goes down, don't
    863 	 * transmit anything.  That way, we'll be restarted by the periodic
    864 	 * interrupt when CTS comes back up.
    865 	 */
    866 	if (ISCTS(ciab.pra))
    867 		ser_putchar(tp, *sob_ptr++);
    868 	else
    869 		CLRCTS(last_ciab_pra);	/* Remember that CTS is off */
    870 out:
    871 	splx(s);
    872 }
    873 
    874 void
    875 serstart(tp)
    876 	struct tty *tp;
    877 {
    878 	int cc, s, hiwat;
    879 #ifdef DIAGNOSTIC
    880 	int unit;
    881 #endif
    882 
    883 	hiwat = 0;
    884 
    885 	if ((tp->t_state & TS_ISOPEN) == 0)
    886 		return;
    887 
    888 #ifdef DIAGNOSTIC
    889 	unit = SERUNIT(tp->t_dev);
    890 	if (unit)
    891 		panic("serstart: unit is %d\n", unit);
    892 #endif
    893 
    894 	s = spltty();
    895 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    896 		goto out;
    897 
    898 	cc = tp->t_outq.c_cc;
    899 	if (cc <= tp->t_lowat) {
    900 		if (tp->t_state & TS_ASLEEP) {
    901 			tp->t_state &= ~TS_ASLEEP;
    902 			wakeup((caddr_t) & tp->t_outq);
    903 		}
    904 		selwakeup(&tp->t_wsel);
    905 	}
    906 	if (cc == 0 || (tp->t_state & TS_BUSY))
    907 		goto out;
    908 
    909 	/*
    910 	 * We only do bulk transfers if using CTSRTS flow control, not for
    911 	 * (probably sloooow) ixon/ixoff devices.
    912 	 */
    913 	if ((tp->t_cflag & CRTSCTS) == 0)
    914 		cc = 1;
    915 
    916 	/*
    917 	 * Limit the amount of output we do in one burst
    918 	 * to prevent hogging the CPU.
    919 	 */
    920 	if (cc > SEROBUF_SIZE) {
    921 		hiwat++;
    922 		cc = SEROBUF_SIZE;
    923 	}
    924 	cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
    925 	if (cc > 0) {
    926 		tp->t_state |= TS_BUSY;
    927 
    928 		sob_ptr = ser_outbuf;
    929 		sob_end = ser_outbuf + cc;
    930 
    931 		/*
    932 		 * Get first character out, then have TBE-interrupts blow out
    933 		 * further characters, until buffer is empty, and TS_BUSY gets
    934 		 * cleared.
    935 		 */
    936 		ser_putchar(tp, *sob_ptr++);
    937 	}
    938 out:
    939 	splx(s);
    940 }
    941 
    942 /*
    943  * Stop output on a line.
    944  */
    945 /*ARGSUSED*/
    946 void
    947 serstop(tp, flag)
    948 	struct tty *tp;
    949 	int flag;
    950 {
    951 	int s;
    952 
    953 	s = spltty();
    954 	if (tp->t_state & TS_BUSY) {
    955 		if ((tp->t_state & TS_TTSTOP) == 0)
    956 			tp->t_state |= TS_FLUSH;
    957 	}
    958 	splx(s);
    959 }
    960 
    961 int
    962 sermctl(dev, bits, how)
    963 	dev_t dev;
    964 	int bits, how;
    965 {
    966 	int s;
    967 	u_char ub = 0;
    968 
    969 	/*
    970 	 * convert TIOCM* mask into CIA mask
    971 	 * which is active low
    972 	 */
    973 	if (how != DMGET) {
    974 		ub = 0;
    975 		if (bits & TIOCM_DTR)
    976 			ub |= CIAB_PRA_DTR;
    977 		if (bits & TIOCM_RTS)
    978 			ub |= CIAB_PRA_RTS;
    979 		if (bits & TIOCM_CTS)
    980 			ub |= CIAB_PRA_CTS;
    981 		if (bits & TIOCM_CD)
    982 			ub |= CIAB_PRA_CD;
    983 		if (bits & TIOCM_RI)
    984 			ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    985 		if (bits & TIOCM_DSR)
    986 			ub |= CIAB_PRA_DSR;
    987 	}
    988 	s = spltty();
    989 	switch (how) {
    990 	case DMSET:
    991 		/* invert and set */
    992 		ciab.pra = ~ub;
    993 		break;
    994 
    995 	case DMBIC:
    996 		ciab.pra |= ub;
    997 		ub = ~ciab.pra;
    998 		break;
    999 
   1000 	case DMBIS:
   1001 		ciab.pra &= ~ub;
   1002 		ub = ~ciab.pra;
   1003 		break;
   1004 
   1005 	case DMGET:
   1006 		ub = ~ciab.pra;
   1007 		break;
   1008 	}
   1009 	(void)splx(s);
   1010 
   1011 	bits = 0;
   1012 	if (ub & CIAB_PRA_DTR)
   1013 		bits |= TIOCM_DTR;
   1014 	if (ub & CIAB_PRA_RTS)
   1015 		bits |= TIOCM_RTS;
   1016 	if (ub & CIAB_PRA_CTS)
   1017 		bits |= TIOCM_CTS;
   1018 	if (ub & CIAB_PRA_CD)
   1019 		bits |= TIOCM_CD;
   1020 	if (ub & CIAB_PRA_SEL)
   1021 		bits |= TIOCM_RI;
   1022 	if (ub & CIAB_PRA_DSR)
   1023 		bits |= TIOCM_DSR;
   1024 
   1025 	return(bits);
   1026 }
   1027 
   1028 /*
   1029  * Following are all routines needed for SER to act as console
   1030  */
   1031 void
   1032 sercnprobe(cp)
   1033 	struct consdev *cp;
   1034 {
   1035 	int unit;
   1036 
   1037 	/* locate the major number */
   1038 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
   1039 		if (cdevsw[sermajor].d_open == (void *)seropen)
   1040 			break;
   1041 
   1042 
   1043 	unit = CONUNIT;			/* XXX: ick */
   1044 
   1045 	/*
   1046 	 * initialize required fields
   1047 	 */
   1048 	cp->cn_dev = makedev(sermajor, unit);
   1049 	if (serconsole == unit)
   1050 		cp->cn_pri = CN_REMOTE;
   1051 	else
   1052 		cp->cn_pri = CN_NORMAL;
   1053 #ifdef KGDB
   1054 	if (major(kgdb_dev) == 1)	/* XXX */
   1055 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
   1056 #endif
   1057 }
   1058 
   1059 void
   1060 sercninit(cp)
   1061 	struct consdev *cp;
   1062 {
   1063 	int unit;
   1064 
   1065 	unit = SERUNIT(cp->cn_dev);
   1066 
   1067 	serinit(serdefaultrate);
   1068 	serconsole = unit;
   1069 	serconsinit = 1;
   1070 }
   1071 
   1072 void
   1073 serinit(rate)
   1074 	int rate;
   1075 {
   1076 	int s;
   1077 
   1078 	s = splser();
   1079 	/*
   1080 	 * might want to fiddle with the CIA later ???
   1081 	 */
   1082 	custom.serper = (rate>=110 ? SERBRD(rate) : 0);
   1083 	splx(s);
   1084 }
   1085 
   1086 int
   1087 sercngetc(dev)
   1088 	dev_t dev;
   1089 {
   1090 	u_short stat;
   1091 	int c, s;
   1092 
   1093 	s = splser();
   1094 	/*
   1095 	 * poll
   1096 	 */
   1097 	while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
   1098 		;
   1099 	c = stat & 0xff;
   1100 	/*
   1101 	 * clear interrupt
   1102 	 */
   1103 	custom.intreq = INTF_RBF;
   1104 	splx(s);
   1105 	return(c);
   1106 }
   1107 
   1108 /*
   1109  * Console kernel output character routine.
   1110  */
   1111 void
   1112 sercnputc(dev, c)
   1113 	dev_t dev;
   1114 	int c;
   1115 {
   1116 	register int timo;
   1117 	int s;
   1118 
   1119 	s = splhigh();
   1120 
   1121 	if (serconsinit == 0) {
   1122 		(void)serinit(serdefaultrate);
   1123 		serconsinit = 1;
   1124 	}
   1125 
   1126 	/*
   1127 	 * wait for any pending transmission to finish
   1128 	 */
   1129 	timo = 50000;
   1130 	while (!(custom.serdatr & SERDATRF_TBE) && --timo);
   1131 
   1132 	/*
   1133 	 * transmit char.
   1134 	 */
   1135 	custom.serdat = (c & 0xff) | 0x100;
   1136 
   1137 	/*
   1138 	 * wait for this transmission to complete
   1139 	 */
   1140 	timo = 1500000;
   1141 	while (!(custom.serdatr & SERDATRF_TBE) && --timo)
   1142 		;
   1143 
   1144 	/*
   1145 	 * Wait for the device (my vt100..) to process the data, since we
   1146 	 * don't do flow-control with cnputc
   1147 	 */
   1148 	for (timo = 0; timo < 30000; timo++)
   1149 		;
   1150 
   1151 	/*
   1152 	 * clear any interrupts generated by this transmission
   1153 	 */
   1154 	custom.intreq = INTF_TBE;
   1155 	splx(s);
   1156 }
   1157 
   1158 void
   1159 sercnpollc(dev, on)
   1160 	dev_t dev;
   1161 	int on;
   1162 {
   1163 }
   1164 #endif
   1165