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