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