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