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