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