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