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