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