Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.45
      1 /*	$NetBSD: ser.c,v 1.45 1998/06/26 17:50:20 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, 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, DMSET);
    781 		custom.serper = (0 << 15) | ospeed;
    782 	}
    783 	(void)(*linesw[tp->t_line].l_modem)(tp, ISDCD(last_ciab_pra));
    784 
    785 	return(0);
    786 }
    787 
    788 int serhwiflow(tp, flag)
    789         struct tty *tp;
    790         int flag;
    791 {
    792 #if 0
    793 	printf ("serhwiflow %d\n", flag);
    794 #endif
    795         if (flag)
    796 		CLRRTS(ciab.pra);
    797 	else
    798 	        SETRTS(ciab.pra);
    799         return 1;
    800 }
    801 
    802 static void
    803 ser_putchar(tp, c)
    804 	struct tty *tp;
    805 	u_short c;
    806 {
    807 	if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
    808 		c &= 0x7f;
    809 
    810 	/*
    811 	 * handle parity if necessary
    812 	 */
    813 	if (tp->t_cflag & PARENB) {
    814 		if (even_parity[c])
    815 			c |= 0x80;
    816 		if (tp->t_cflag & PARODD)
    817 			c ^= 0x80;
    818 	}
    819 	/*
    820 	 * add stop bit(s)
    821 	 */
    822 	if (tp->t_cflag & CSTOPB)
    823 		c |= 0x300;
    824 	else
    825 		c |= 0x100;
    826 
    827 	custom.serdat = c;
    828 }
    829 
    830 
    831 static u_char ser_outbuf[SEROBUF_SIZE];
    832 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
    833 
    834 void
    835 ser_outintr()
    836 {
    837 	struct tty *tp;
    838 	int s;
    839 
    840 	tp = ser_tty;
    841 	s = spltty();
    842 
    843 	if (tp == 0)
    844 		goto out;
    845 
    846 	if ((custom.intreqr & INTF_TBE) == 0)
    847 		goto out;
    848 
    849 	/*
    850 	 * clear interrupt
    851 	 */
    852 	custom.intreq = INTF_TBE;
    853 
    854 	if (sob_ptr == sob_end) {
    855 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    856 		if (tp->t_line)
    857 			(*linesw[tp->t_line].l_start)(tp);
    858 		else
    859 			serstart(tp);
    860 		goto out;
    861 	}
    862 
    863 	/*
    864 	 * Do hardware flow control here.  if the CTS line goes down, don't
    865 	 * transmit anything.  That way, we'll be restarted by the periodic
    866 	 * interrupt when CTS comes back up.
    867 	 */
    868 	if (ISCTS(ciab.pra))
    869 		ser_putchar(tp, *sob_ptr++);
    870 	else
    871 		CLRCTS(last_ciab_pra);	/* Remember that CTS is off */
    872 out:
    873 	splx(s);
    874 }
    875 
    876 void
    877 serstart(tp)
    878 	struct tty *tp;
    879 {
    880 	int cc, s, hiwat;
    881 #ifdef DIAGNOSTIC
    882 	int unit;
    883 #endif
    884 
    885 	hiwat = 0;
    886 
    887 	if ((tp->t_state & TS_ISOPEN) == 0)
    888 		return;
    889 
    890 #ifdef DIAGNOSTIC
    891 	unit = SERUNIT(tp->t_dev);
    892 	if (unit)
    893 		panic("serstart: unit is %d\n", unit);
    894 #endif
    895 
    896 	s = spltty();
    897 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    898 		goto out;
    899 
    900 	cc = tp->t_outq.c_cc;
    901 	if (cc <= tp->t_lowat) {
    902 		if (tp->t_state & TS_ASLEEP) {
    903 			tp->t_state &= ~TS_ASLEEP;
    904 			wakeup((caddr_t) & tp->t_outq);
    905 		}
    906 		selwakeup(&tp->t_wsel);
    907 	}
    908 	if (cc == 0 || (tp->t_state & TS_BUSY))
    909 		goto out;
    910 
    911 	/*
    912 	 * We only do bulk transfers if using CTSRTS flow control, not for
    913 	 * (probably sloooow) ixon/ixoff devices.
    914 	 */
    915 	if ((tp->t_cflag & CRTSCTS) == 0)
    916 		cc = 1;
    917 
    918 	/*
    919 	 * Limit the amount of output we do in one burst
    920 	 * to prevent hogging the CPU.
    921 	 */
    922 	if (cc > SEROBUF_SIZE) {
    923 		hiwat++;
    924 		cc = SEROBUF_SIZE;
    925 	}
    926 	cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
    927 	if (cc > 0) {
    928 		tp->t_state |= TS_BUSY;
    929 
    930 		sob_ptr = ser_outbuf;
    931 		sob_end = ser_outbuf + cc;
    932 
    933 		/*
    934 		 * Get first character out, then have TBE-interrupts blow out
    935 		 * further characters, until buffer is empty, and TS_BUSY gets
    936 		 * cleared.
    937 		 */
    938 		ser_putchar(tp, *sob_ptr++);
    939 	}
    940 out:
    941 	splx(s);
    942 }
    943 
    944 /*
    945  * Stop output on a line.
    946  */
    947 /*ARGSUSED*/
    948 void
    949 serstop(tp, flag)
    950 	struct tty *tp;
    951 	int flag;
    952 {
    953 	int s;
    954 
    955 	s = spltty();
    956 	if (tp->t_state & TS_BUSY) {
    957 		if ((tp->t_state & TS_TTSTOP) == 0)
    958 			tp->t_state |= TS_FLUSH;
    959 	}
    960 	splx(s);
    961 }
    962 
    963 int
    964 sermctl(dev, bits, how)
    965 	dev_t dev;
    966 	int bits, how;
    967 {
    968 	int s;
    969 	u_char ub = 0;
    970 
    971 	/*
    972 	 * convert TIOCM* mask into CIA mask
    973 	 * which is active low
    974 	 */
    975 	if (how != DMGET) {
    976 		ub = 0;
    977 		if (bits & TIOCM_DTR)
    978 			ub |= CIAB_PRA_DTR;
    979 		if (bits & TIOCM_RTS)
    980 			ub |= CIAB_PRA_RTS;
    981 		if (bits & TIOCM_CTS)
    982 			ub |= CIAB_PRA_CTS;
    983 		if (bits & TIOCM_CD)
    984 			ub |= CIAB_PRA_CD;
    985 		if (bits & TIOCM_RI)
    986 			ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    987 		if (bits & TIOCM_DSR)
    988 			ub |= CIAB_PRA_DSR;
    989 	}
    990 	s = spltty();
    991 	switch (how) {
    992 	case DMSET:
    993 		/* invert and set */
    994 		ciab.pra = ~ub;
    995 		break;
    996 
    997 	case DMBIC:
    998 		ciab.pra |= ub;
    999 		ub = ~ciab.pra;
   1000 		break;
   1001 
   1002 	case DMBIS:
   1003 		ciab.pra &= ~ub;
   1004 		ub = ~ciab.pra;
   1005 		break;
   1006 
   1007 	case DMGET:
   1008 		ub = ~ciab.pra;
   1009 		break;
   1010 	}
   1011 	(void)splx(s);
   1012 
   1013 	bits = 0;
   1014 	if (ub & CIAB_PRA_DTR)
   1015 		bits |= TIOCM_DTR;
   1016 	if (ub & CIAB_PRA_RTS)
   1017 		bits |= TIOCM_RTS;
   1018 	if (ub & CIAB_PRA_CTS)
   1019 		bits |= TIOCM_CTS;
   1020 	if (ub & CIAB_PRA_CD)
   1021 		bits |= TIOCM_CD;
   1022 	if (ub & CIAB_PRA_SEL)
   1023 		bits |= TIOCM_RI;
   1024 	if (ub & CIAB_PRA_DSR)
   1025 		bits |= TIOCM_DSR;
   1026 
   1027 	return(bits);
   1028 }
   1029 
   1030 /*
   1031  * Following are all routines needed for SER to act as console
   1032  */
   1033 void
   1034 sercnprobe(cp)
   1035 	struct consdev *cp;
   1036 {
   1037 	int unit;
   1038 
   1039 	/* locate the major number */
   1040 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
   1041 		if (cdevsw[sermajor].d_open == (void *)seropen)
   1042 			break;
   1043 
   1044 
   1045 	unit = CONUNIT;			/* XXX: ick */
   1046 
   1047 	/*
   1048 	 * initialize required fields
   1049 	 */
   1050 	cp->cn_dev = makedev(sermajor, unit);
   1051 	if (serconsole == unit)
   1052 		cp->cn_pri = CN_REMOTE;
   1053 	else
   1054 		cp->cn_pri = CN_NORMAL;
   1055 #ifdef KGDB
   1056 	if (major(kgdb_dev) == 1)	/* XXX */
   1057 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
   1058 #endif
   1059 }
   1060 
   1061 void
   1062 sercninit(cp)
   1063 	struct consdev *cp;
   1064 {
   1065 	int unit;
   1066 
   1067 	unit = SERUNIT(cp->cn_dev);
   1068 
   1069 	serinit(serdefaultrate);
   1070 	serconsole = unit;
   1071 	serconsinit = 1;
   1072 }
   1073 
   1074 void
   1075 serinit(rate)
   1076 	int rate;
   1077 {
   1078 	int s;
   1079 
   1080 	s = splser();
   1081 	/*
   1082 	 * might want to fiddle with the CIA later ???
   1083 	 */
   1084 	custom.serper = (rate>=110 ? SERBRD(rate) : 0);
   1085 	splx(s);
   1086 }
   1087 
   1088 int
   1089 sercngetc(dev)
   1090 	dev_t dev;
   1091 {
   1092 	u_short stat;
   1093 	int c, s;
   1094 
   1095 	s = splser();
   1096 	/*
   1097 	 * poll
   1098 	 */
   1099 	while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
   1100 		;
   1101 	c = stat & 0xff;
   1102 	/*
   1103 	 * clear interrupt
   1104 	 */
   1105 	custom.intreq = INTF_RBF;
   1106 	splx(s);
   1107 	return(c);
   1108 }
   1109 
   1110 /*
   1111  * Console kernel output character routine.
   1112  */
   1113 void
   1114 sercnputc(dev, c)
   1115 	dev_t dev;
   1116 	int c;
   1117 {
   1118 	register int timo;
   1119 	int s;
   1120 
   1121 	s = splhigh();
   1122 
   1123 	if (serconsinit == 0) {
   1124 		(void)serinit(serdefaultrate);
   1125 		serconsinit = 1;
   1126 	}
   1127 
   1128 	/*
   1129 	 * wait for any pending transmission to finish
   1130 	 */
   1131 	timo = 50000;
   1132 	while (!(custom.serdatr & SERDATRF_TBE) && --timo);
   1133 
   1134 	/*
   1135 	 * transmit char.
   1136 	 */
   1137 	custom.serdat = (c & 0xff) | 0x100;
   1138 
   1139 	/*
   1140 	 * wait for this transmission to complete
   1141 	 */
   1142 	timo = 1500000;
   1143 	while (!(custom.serdatr & SERDATRF_TBE) && --timo)
   1144 		;
   1145 
   1146 	/*
   1147 	 * Wait for the device (my vt100..) to process the data, since we
   1148 	 * don't do flow-control with cnputc
   1149 	 */
   1150 	for (timo = 0; timo < 30000; timo++)
   1151 		;
   1152 
   1153 	/*
   1154 	 * clear any interrupts generated by this transmission
   1155 	 */
   1156 	custom.intreq = INTF_TBE;
   1157 	splx(s);
   1158 }
   1159 
   1160 void
   1161 sercnpollc(dev, on)
   1162 	dev_t dev;
   1163 	int on;
   1164 {
   1165 }
   1166 #endif
   1167