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