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