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