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