Home | History | Annotate | Line # | Download | only in dev
mfc.c revision 1.2
      1 /*
      2  * Copyright (c) 1994 Michael L. Hitch
      3  * Copyright (c) 1982, 1990 The Regents of the University of California.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed by the University of
     17  *	California, Berkeley and its contributors.
     18  * 4. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  *	@(#)mfc.c
     35  *	$Id: mfc.c,v 1.2 1995/02/12 19:19:16 chopps Exp $
     36  */
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/kernel.h>
     41 #include <sys/device.h>
     42 #include <sys/tty.h>
     43 #include <sys/proc.h>
     44 #include <sys/conf.h>
     45 #include <sys/file.h>
     46 #include <sys/malloc.h>
     47 #include <sys/uio.h>
     48 #include <sys/kernel.h>
     49 #include <sys/syslog.h>
     50 #include <sys/queue.h>
     51 #include <machine/cpu.h>
     52 #include <amiga/amiga/device.h>
     53 #include <amiga/amiga/isr.h>
     54 #include <amiga/amiga/custom.h>
     55 #include <amiga/amiga/cia.h>
     56 #include <amiga/amiga/cc.h>
     57 #include <amiga/dev/zbusvar.h>
     58 
     59 #include <dev/cons.h>
     60 
     61 #include "mfcs.h"
     62 
     63 #define SEROBUF_SIZE	128
     64 #define SERIBUF_SIZE	1024
     65 
     66 #define splser()	spl6()
     67 
     68 /*
     69  * 68581 DUART registers
     70  */
     71 struct mfc_regs {
     72 	volatile u_char du_mr1a;
     73 #define	du_mr2a		du_mr1a
     74 	u_char pad0;
     75 	volatile u_char du_csra;
     76 #define	du_sra		du_csra
     77 	u_char pad2;
     78 	volatile u_char du_cra;
     79 	u_char pad4;
     80 	volatile u_char du_tba;
     81 #define	du_rba		du_tba
     82 	u_char pad6;
     83 	volatile u_char du_acr;
     84 #define	du_ipcr		du_acr
     85 	u_char pad8;
     86 	volatile u_char du_imr;
     87 #define	du_isr		du_imr
     88 	u_char pad10;
     89 	volatile u_char du_ctur;
     90 #define	du_cmsb		du_ctur
     91 	u_char pad12;
     92 	volatile u_char du_ctlr;
     93 #define	du_clsb		du_ctlr
     94 	u_char pad14;
     95 	volatile u_char du_mr1b;
     96 #define	du_mr2b		du_mr1b
     97 	u_char pad16;
     98 	volatile u_char du_csrb;
     99 #define	du_srb		du_csrb
    100 	u_char pad18;
    101 	volatile u_char du_crb;
    102 	u_char pad20;
    103 	volatile u_char du_tbb;
    104 #define	du_rbb		du_tbb
    105 	u_char pad22;
    106 	volatile u_char du_ivr;
    107 	u_char pad24;
    108 	volatile u_char du_opcr;
    109 #define	du_ip		du_opcr
    110 	u_char pad26;
    111 	volatile u_char du_btst;
    112 #define	du_strc		du_btst
    113 	u_char pad28;
    114 	volatile u_char du_btrst;
    115 #define	du_stpc		du_btrst
    116 	u_char pad30;
    117 };
    118 
    119 /*
    120  * 68681 DUART serial port registers
    121  */
    122 struct duart_regs {
    123 	volatile u_char ch_mr1;
    124 #define	ch_mr2		ch_mr1
    125 	u_char pad0;
    126 	volatile u_char	ch_csr;
    127 #define	ch_sr		ch_csr
    128 	u_char pad1;
    129 	volatile u_char	ch_cr;
    130 	u_char pad2;
    131 	volatile u_char	ch_tb;
    132 #define	ch_rb		ch_tb
    133 	u_char pad3;
    134 };
    135 
    136 struct mfc_softc {
    137 	struct	device sc_dev;
    138 	struct	isr sc_isr;
    139 	struct	mfc_regs *sc_regs;
    140 	u_long	clk_frq;
    141 	u_short	ct_val;
    142 	u_char	ct_usecnt;
    143 	u_char	imask;
    144 	u_char	mfc_iii;
    145 	u_char	last_ip;
    146 };
    147 
    148 #if NMFCS > 0
    149 struct mfcs_softc {
    150 	struct	device sc_dev;
    151 	struct	duart_regs *sc_duart;
    152 	struct	mfc_regs *sc_regs;
    153 	struct	mfc_softc *sc_mfc;
    154 	long	flags;			/* XXX */
    155 #define CT_USED	1			/* CT in use */
    156 	u_short	*rptr, *wptr, incnt, ovfl;
    157 	u_short	inbuf[SERIBUF_SIZE];
    158 	char	*ptr, *end;
    159 	char	outbuf[SEROBUF_SIZE];
    160 };
    161 #endif
    162 
    163 #if NMFCP > 0
    164 struct mfcp_softc {
    165 };
    166 #endif
    167 
    168 struct mfc_args {
    169 	struct zbus_args zargs;
    170 	char	*subdev;
    171 	char	unit;
    172 };
    173 
    174 int mfcprint __P((void *auxp, char *));
    175 void mfcattach __P((struct device *, struct device *, void *));
    176 int mfcmatch __P((struct device *, struct cfdata *, void *));
    177 #if NMFCS > 0
    178 void mfcsattach __P((struct device *, struct device *, void *));
    179 int mfcsmatch __P((struct device *, struct cfdata *, void *));
    180 #endif
    181 #if NMFCP > 0
    182 void mfcpattach __P((struct device *, struct device *, void *));
    183 int mfcpmatch __P((struct device *, struct cfdata *, void *));
    184 #endif
    185 int mfcintr __P((struct mfc_softc *));
    186 void mfcsmint __P((register int unit));
    187 
    188 struct cfdriver mfccd = {
    189 	NULL, "mfc", (cfmatch_t) mfcmatch, mfcattach,
    190 	DV_DULL, sizeof(struct mfc_softc), NULL, 0 };
    191 
    192 #if NMFCS > 0
    193 struct cfdriver mfcscd = {
    194 	NULL, "mfcs", (cfmatch_t) mfcsmatch, mfcsattach,
    195 	DV_TTY, sizeof(struct mfcs_softc), NULL, 0 };
    196 #endif
    197 
    198 #if NMFCP > 0
    199 struct cfdriver mfcpcd = {
    200 	NULL, "mfcp", (cfmatch_t) mfcpmatch, mfcpattach,
    201 	DV_DULL, sizeof(struct mfcp_softc), NULL, 0 };
    202 #endif
    203 
    204 int	mfcsstart(), mfcsparam(), mfcshwiflow();
    205 int	mfcs_active;
    206 int	mfcsdefaultrate = 38400 /*TTYDEF_SPEED*/;
    207 int	mfcsswflags[NMFCS];
    208 #define SWFLAGS(dev) (mfcsswflags[dev & 31] | (((dev) & 0x80) == 0 ? TIOCFLAG_SOFTCAR : 0))
    209 
    210 struct	vbl_node mfcs_vbl_node[NMFCS];
    211 struct	tty *mfcs_tty[NMFCS + 128];
    212 
    213 struct speedtab mfcs3speedtab[] = {
    214 	0,	0,
    215 	150,	0x00,
    216 	200,	0x11,
    217 	300,	0x33,
    218 	600,	0x44,
    219 	1200,	0x55,
    220 	2400,	0x66,
    221 	4800,	0x88,
    222 	9600,	0x99,
    223 	19200,	0xbb,
    224 	38400,	0xcc,
    225 	-1,	-1
    226 };
    227 
    228 struct speedtab mfcs2speedtab[] = {
    229 	0,	0,
    230 	75,	0x00,
    231 	100,	0x11,
    232 	150,	0x33,
    233 	300,	0x44,
    234 	600,	0x55,
    235 	1200,	0x66,
    236 	2400,	0x88,
    237  	4800,	0x99,
    238 	9600,	0xbb,
    239 	19200,	0xcc,
    240 	-1,	-1
    241 };
    242 
    243 /*
    244  * if we are an bsc/Alf Data MultFaceCard (I, II, and III)
    245  */
    246 int
    247 mfcmatch(pdp, cdp, auxp)
    248 	struct device *pdp;
    249 	struct cfdata *cdp;
    250 	void *auxp;
    251 {
    252 	struct zbus_args *zap;
    253 
    254 	zap = auxp;
    255 	if (zap->manid == 2092 &&
    256 	    (zap->prodid == 16 || zap->prodid == 17 || zap->prodid == 18))
    257 
    258 		return(1);
    259 	return(0);
    260 }
    261 
    262 void
    263 mfcattach(pdp, dp, auxp)
    264 	struct device *pdp, *dp;
    265 	void *auxp;
    266 {
    267 	struct mfc_softc *scc;
    268 	struct zbus_args *zap;
    269 	struct mfc_args ma;
    270 	int unit;
    271 	struct mfc_regs *rp;
    272 
    273 	zap = auxp;
    274 
    275 	printf ("\n");
    276 
    277 	scc = (struct mfc_softc *)dp;
    278 	unit = scc->sc_dev.dv_unit;
    279 	scc->sc_regs = rp = zap->va;
    280 	if (zap->prodid == 18)
    281 		scc->mfc_iii = 3;
    282 	scc->clk_frq = scc->mfc_iii ? 230400 : 115200;
    283 
    284 	rp->du_opcr = 0x00;		/* configure output port? */
    285 	rp->du_btrst = 0x0f;		/* clear modem lines */
    286 	rp->du_ivr = 0;			/* IVR */
    287 	rp->du_imr = 0;			/* IMR */
    288 	rp->du_acr = 0xe0;		/* baud rate generate set 2 */
    289 	rp->du_ctur = 0;
    290 	rp->du_ctlr = 4;
    291 	rp->du_csra = 0xcc;		/* clock select = 38400 */
    292 	rp->du_cra = 0x10;		/* reset mode register ptr */
    293 	rp->du_cra = 0x20;
    294 	rp->du_cra = 0x30;
    295 	rp->du_cra = 0x40;
    296 	rp->du_mr1a = 0x93;		/* MRA1 */
    297 	rp->du_mr2a = 0x17;		/* MRA2 */
    298 	rp->du_csrb = 0xcc;		/* clock select = 38400 */
    299 	rp->du_crb = 0x10;		/* reset mode register ptr */
    300 	rp->du_crb = 0x20;
    301 	rp->du_crb = 0x30;
    302 	rp->du_crb = 0x40;
    303 	rp->du_mr1b = 0x93;		/* MRB1 */
    304 	rp->du_mr2b = 0x17;		/* MRB2 */
    305 	rp->du_cra = 0x05;		/* enable A Rx & Tx */
    306 	rp->du_crb = 0x05;		/* enable B Rx & Tx */
    307 
    308 	scc->sc_isr.isr_intr = mfcintr;
    309 	scc->sc_isr.isr_arg = scc;
    310 	scc->sc_isr.isr_ipl = 6;
    311 	add_isr(&scc->sc_isr);
    312 
    313 	/* configure ports */
    314 	bcopy(zap, &ma.zargs, sizeof(struct zbus_args));
    315 	ma.subdev = "mfcs";
    316 	ma.unit = unit * 2;
    317 	config_found(dp, &ma, mfcprint);
    318 	ma.unit = unit * 2 + 1;
    319 	config_found(dp, &ma, mfcprint);
    320 	ma.subdev = "mfcp";
    321 	ma.unit = unit;
    322 	config_found(dp, &ma, mfcprint);
    323 }
    324 
    325 /*
    326  *
    327  */
    328 int
    329 mfcsmatch(pdp, cdp, auxp)
    330 	struct device *pdp;
    331 	struct cfdata *cdp;
    332 	void *auxp;
    333 {
    334 	struct mfc_args *ma;
    335 
    336 	ma = auxp;
    337 	if (strcmp(ma->subdev, "mfcs") == 0)
    338 		return (1);
    339 	return (0);
    340 }
    341 
    342 void
    343 mfcsattach(pdp, dp, auxp)
    344 	struct device *pdp, *dp;
    345 	void *auxp;
    346 {
    347 	int unit;
    348 	struct mfcs_softc *sc;
    349 	struct mfc_softc *scc;
    350 	struct mfc_args *ma;
    351 	struct mfc_regs *rp;
    352 
    353 	sc = (struct mfcs_softc *) dp;
    354 	scc = (struct mfc_softc *) pdp;
    355 	ma = auxp;
    356 
    357 	if (dp) {
    358 		printf (": input fifo %d output fifo %d\n", SERIBUF_SIZE,
    359 		    SEROBUF_SIZE);
    360 		alloc_sicallback();
    361 	}
    362 
    363 	unit = ma->unit;
    364 	mfcs_active |= 1 << unit;
    365 	sc->rptr = sc->wptr = sc->inbuf;
    366 	sc->sc_mfc = scc;
    367 	sc->sc_regs = rp = scc->sc_regs;
    368 	sc->sc_duart = (struct duart_regs *) ((unit & 1) ? &rp->du_mr1b :
    369 	    &rp->du_mr1a);
    370 	/*
    371 	 * should have only one vbl routine to handle all ports?
    372 	 */
    373 	mfcs_vbl_node[unit].function = (void (*) (void *)) mfcsmint;
    374 	mfcs_vbl_node[unit].data = (void *) unit;
    375 	add_vbl_function(&mfcs_vbl_node[unit], 1, (void *) unit);
    376 }
    377 
    378 /*
    379  * print diag if pnp is NULL else just extra
    380  */
    381 int
    382 mfcprint(auxp, pnp)
    383 	void *auxp;
    384 	char *pnp;
    385 {
    386 	if (pnp == NULL)
    387 		return(UNCONF);
    388 	return(QUIET);
    389 }
    390 
    391 int
    392 mfcsopen(dev, flag, mode, p)
    393 	dev_t dev;
    394 	int flag, mode;
    395 	struct proc *p;
    396 {
    397 	struct tty *tp;
    398 	int unit, error, s;
    399 
    400 	error = 0;
    401 	unit = dev & 0x1f;
    402 
    403 	if (unit >= NMFCS || (mfcs_active & (1 << unit)) == 0)
    404 		return (ENXIO);
    405 
    406 	s = spltty();
    407 
    408 	if (mfcs_tty[unit])
    409 		tp = mfcs_tty[unit];
    410 	else
    411 		tp = mfcs_tty[unit] = mfcs_tty[unit + 128] = ttymalloc();
    412 
    413 	tp->t_oproc = (void (*) (struct tty *)) mfcsstart;
    414 	tp->t_param = mfcsparam;
    415 	tp->t_dev = dev;
    416 	tp->t_hwiflow = mfcshwiflow;
    417 
    418 	if ((tp->t_state & TS_ISOPEN) == 0) {
    419 		tp->t_state |= TS_WOPEN;
    420 		ttychars(tp);
    421 		if (tp->t_ispeed == 0) {
    422 			/*
    423 			 * only when cleared do we reset to defaults.
    424 			 */
    425 			tp->t_iflag = TTYDEF_IFLAG;
    426 			tp->t_oflag = TTYDEF_OFLAG;
    427 			tp->t_cflag = TTYDEF_CFLAG;
    428 			tp->t_lflag = TTYDEF_LFLAG;
    429 			tp->t_ispeed = tp->t_ospeed = mfcsdefaultrate;
    430 		}
    431 		/*
    432 		 * do these all the time
    433 		 */
    434 		if (mfcsswflags[unit] & TIOCFLAG_CLOCAL)
    435 			tp->t_cflag |= CLOCAL;
    436 		if (mfcsswflags[unit] & TIOCFLAG_CRTSCTS)
    437 			tp->t_cflag |= CRTSCTS;
    438 		if (mfcsswflags[unit] & TIOCFLAG_MDMBUF)
    439 			tp->t_cflag |= MDMBUF;
    440 		mfcsparam(tp, &tp->t_termios);
    441 		ttsetwater(tp);
    442 
    443 		(void)mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    444 		if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
    445 		    (mfcsmctl(dev, 0, DMGET) & TIOCM_CD))
    446 			tp->t_state |= TS_CARR_ON;
    447 		else
    448 			tp->t_state &= ~TS_CARR_ON;
    449 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
    450 		splx(s);
    451 		return(EBUSY);
    452 	}
    453 
    454 	/*
    455 	 * if NONBLOCK requested, ignore carrier
    456 	 */
    457 	if (flag & O_NONBLOCK)
    458 		goto done;
    459 
    460 	/*
    461 	 * block waiting for carrier
    462 	 */
    463 	while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
    464 		tp->t_state |= TS_WOPEN;
    465 		error = ttysleep(tp, (caddr_t)&tp->t_rawq,
    466 		    TTIPRI | PCATCH, ttopen, 0);
    467 		if (error) {
    468 			splx(s);
    469 			return(error);
    470 		}
    471 	}
    472 done:
    473 	/* This is a way to handle lost XON characters */
    474 	if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
    475 		tp->t_state &= ~TS_TTSTOP;
    476 	        ttstart (tp);
    477 	}
    478 
    479 	splx(s);
    480 	/*
    481 	 * Reset the tty pointer, as there could have been a dialout
    482 	 * use of the tty with a dialin open waiting.
    483 	 */
    484 	tp->t_dev = dev;
    485 	return((*linesw[tp->t_line].l_open)(dev, tp));
    486 }
    487 
    488 /*ARGSUSED*/
    489 int
    490 mfcsclose(dev, flag, mode, p)
    491 	dev_t dev;
    492 	int flag, mode;
    493 	struct proc *p;
    494 {
    495 	struct tty *tp;
    496 	int unit;
    497 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
    498 	struct mfc_softc *scc= sc->sc_mfc;
    499 
    500 	unit = dev & 31;
    501 
    502 	tp = mfcs_tty[unit];
    503 	(*linesw[tp->t_line].l_close)(tp, flag);
    504 	sc->sc_duart->ch_cr = 0x70;			/* stop break */
    505 
    506 	scc->imask &= ~(0x7 << ((unit & 1) * 4));
    507 	scc->sc_regs->du_imr = scc->imask;
    508 	if (sc->flags & CT_USED) {
    509 		--scc->ct_usecnt;
    510 		sc->flags &= ~CT_USED;
    511 	}
    512 
    513 	/*
    514 	 * If the device is closed, it's close, no matter whether we deal with
    515 	 * modem control signals nor not.
    516 	 */
    517 #if 0
    518 	if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
    519 	    (tp->t_state & TS_ISOPEN) == 0)
    520 #endif
    521 		(void) mfcsmctl(dev, 0, DMSET);
    522 	ttyclose(tp);
    523 #if not_yet
    524 	if (tp != &mfcs_cons) {
    525 		remove_vbl_function(&mfcs_vbl_node[unit]);
    526 		ttyfree(tp);
    527 		mfcs_tty[unit] = (struct tty *) NULL;
    528 	}
    529 #endif
    530 	return (0);
    531 }
    532 
    533 int
    534 mfcsread(dev, uio, flag)
    535 	dev_t dev;
    536 	struct uio *uio;
    537 	int flag;
    538 {
    539 	struct tty *tp;
    540 	if ((tp = mfcs_tty[dev & 31]) == NULL)
    541 		return(ENXIO);
    542 	return((*linesw[tp->t_line].l_read)(tp, uio, flag));
    543 }
    544 
    545 int
    546 mfcswrite(dev, uio, flag)
    547 	dev_t dev;
    548 	struct uio *uio;
    549 	int flag;
    550 {
    551 	struct tty *tp;
    552 
    553 	if ((tp = mfcs_tty[dev & 31]) == NULL)
    554 		return(ENXIO);
    555 	return((*linesw[tp->t_line].l_write)(tp, uio, flag));
    556 }
    557 int
    558 mfcsioctl(dev, cmd, data, flag, p)
    559 	dev_t	dev;
    560 	caddr_t data;
    561 	struct proc *p;
    562 {
    563 	register struct tty *tp;
    564 	register int unit = dev & 31;
    565 	register int error;
    566 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
    567 
    568 	tp = mfcs_tty[unit];
    569 	if (!tp)
    570 		return ENXIO;
    571 
    572 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    573 	if (error >= 0)
    574 		return(error);
    575 
    576 	error = ttioctl(tp, cmd, data, flag, p);
    577 	if (error >= 0)
    578 		return(error);
    579 
    580 	switch (cmd) {
    581 	case TIOCSBRK:
    582 		sc->sc_duart->ch_cr = 0x60;		/* start break */
    583 		break;
    584 
    585 	case TIOCCBRK:
    586 		sc->sc_duart->ch_cr = 0x70;		/* stop break */
    587 		break;
    588 
    589 	case TIOCSDTR:
    590 		(void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    591 		break;
    592 
    593 	case TIOCCDTR:
    594 		(void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    595 		break;
    596 
    597 	case TIOCMSET:
    598 		(void) mfcsmctl(dev, *(int *) data, DMSET);
    599 		break;
    600 
    601 	case TIOCMBIS:
    602 		(void) mfcsmctl(dev, *(int *) data, DMBIS);
    603 		break;
    604 
    605 	case TIOCMBIC:
    606 		(void) mfcsmctl(dev, *(int *) data, DMBIC);
    607 		break;
    608 
    609 	case TIOCMGET:
    610 		*(int *)data = mfcsmctl(dev, 0, DMGET);
    611 		break;
    612 	case TIOCGFLAGS:
    613 		*(int *)data = SWFLAGS(dev);
    614 		break;
    615 	case TIOCSFLAGS:
    616 		error = suser(p->p_ucred, &p->p_acflag);
    617 		if (error != 0)
    618 			return(EPERM);
    619 
    620 		mfcsswflags[unit] = *(int *)data;
    621                 mfcsswflags[unit] &= /* only allow valid flags */
    622                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
    623 		/* XXXX need to change duart parameters!! */
    624 		break;
    625 	default:
    626 		return(ENOTTY);
    627 	}
    628 
    629 	return(0);
    630 }
    631 
    632 int
    633 mfcsparam(tp, t)
    634 	struct tty *tp;
    635 	struct termios *t;
    636 {
    637 	int cfcr, cflag, unit, ospeed;
    638 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
    639 	struct mfc_softc *scc= sc->sc_mfc;
    640 
    641 	cflag = t->c_cflag;
    642 	unit = tp->t_dev & 31;
    643 	if (sc->flags & CT_USED) {
    644 		--scc->ct_usecnt;
    645 		sc->flags &= ~CT_USED;
    646 	}
    647 	ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab :
    648 	    mfcs2speedtab);
    649 
    650 	/*
    651 	 * If Baud Rate Generator can't generate requested speed,
    652 	 * try to use the counter/timer.
    653 	 */
    654 	if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) {
    655 		ospeed = scc->clk_frq / t->c_ospeed;	/* divisor */
    656 		if (scc->ct_usecnt > 0 && scc->ct_val != ospeed)
    657 			ospeed = -1;
    658 		else {
    659 			scc->sc_regs->du_ctur = ospeed >> 8;
    660 			scc->sc_regs->du_ctlr = ospeed;
    661 			scc->ct_val = ospeed;
    662 			++scc->ct_usecnt;
    663 			sc->flags |= CT_USED;
    664 			ospeed = 0xdd;
    665 		}
    666 	}
    667 	/* XXXX 68681 duart could handle split speeds */
    668 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    669 		return(EINVAL);
    670 
    671 	/*
    672 	 * copy to tty
    673 	 */
    674 	tp->t_ispeed = t->c_ispeed;
    675 	tp->t_ospeed = t->c_ospeed;
    676 	tp->t_cflag = cflag;
    677 
    678 	/*
    679 	 * enable interrupts
    680 	 */
    681 	scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80;
    682 	scc->sc_regs->du_imr = scc->imask;
    683 #if defined(DEBUG) && 0
    684 	printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n",
    685 	    t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag);
    686 #endif
    687 	if (ospeed == 0)
    688 		(void)mfcsmctl(tp->t_dev, 0, DMSET);	/* hang up line */
    689 	else {
    690 		/*
    691 		 * (re)enable DTR
    692 		 * and set baud rate. (8 bit mode)
    693 		 */
    694 		(void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    695 		sc->sc_duart->ch_csr = ospeed;
    696 	}
    697 	return(0);
    698 }
    699 
    700 int mfcshwiflow(tp, flag)
    701         struct tty *tp;
    702         int flag;
    703 {
    704 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
    705 	int unit = tp->t_dev & 1;
    706 
    707         if (flag)
    708 		sc->sc_regs->du_btrst = 1 << unit;
    709 	else
    710 		sc->sc_regs->du_btst = 1 << unit;
    711         return 1;
    712 }
    713 
    714 int
    715 mfcsstart(tp)
    716 	struct tty *tp;
    717 {
    718 	int cc, s, unit;
    719 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
    720 	struct mfc_softc *scc= sc->sc_mfc;
    721 
    722 	if ((tp->t_state & TS_ISOPEN) == 0)
    723 		return;
    724 
    725 	unit = tp->t_dev & 1;
    726 
    727 	s = splser();
    728 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    729 		goto out;
    730 
    731 	cc = tp->t_outq.c_cc;
    732 	if (cc <= tp->t_lowat) {
    733 		if (tp->t_state & TS_ASLEEP) {
    734 			tp->t_state &= ~TS_ASLEEP;
    735 			wakeup((caddr_t) & tp->t_outq);
    736 		}
    737 		selwakeup(&tp->t_wsel);
    738 	}
    739 	if (cc == 0 || (tp->t_state & TS_BUSY))
    740 		goto out;
    741 
    742 	/*
    743 	 * We only do bulk transfers if using CTSRTS flow control, not for
    744 	 * (probably sloooow) ixon/ixoff devices.
    745 	 */
    746 	if ((tp->t_cflag & CRTSCTS) == 0)
    747 		cc = 1;
    748 
    749 	/*
    750 	 * Limit the amount of output we do in one burst
    751 	 * to prevent hogging the CPU.
    752 	 */
    753 	if (cc > SEROBUF_SIZE)
    754 		cc = SEROBUF_SIZE;
    755 	cc = q_to_b(&tp->t_outq, sc->outbuf, cc);
    756 	if (cc > 0) {
    757 		tp->t_state |= TS_BUSY;
    758 
    759 		sc->ptr = sc->outbuf;
    760 		sc->end = sc->outbuf + cc;
    761 
    762 		/*
    763 		 * Get first character out, then have TBE-interrupts blow out
    764 		 * further characters, until buffer is empty, and TS_BUSY gets
    765 		 * cleared.
    766 		 */
    767 		sc->sc_duart->ch_tb = *sc->ptr++;
    768 		scc->imask |= 1 << (unit * 4);
    769 		sc->sc_regs->du_imr = scc->imask;
    770 	}
    771 out:
    772 	splx(s);
    773 }
    774 
    775 /*
    776  * Stop output on a line.
    777  */
    778 /*ARGSUSED*/
    779 int
    780 mfcsstop(tp, flag)
    781 	struct tty *tp;
    782 {
    783 	int s;
    784 
    785 	s = splser();
    786 	if (tp->t_state & TS_BUSY) {
    787 		if ((tp->t_state & TS_TTSTOP) == 0)
    788 			tp->t_state |= TS_FLUSH;
    789 	}
    790 	splx(s);
    791 }
    792 
    793 int
    794 mfcsmctl(dev, bits, how)
    795 	dev_t dev;
    796 	int bits, how;
    797 {
    798 	int unit, s;
    799 	u_char ub;
    800 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
    801 
    802 	unit = dev & 1;
    803 
    804 	/*
    805 	 * convert TIOCM* mask into CIA mask
    806 	 * which is active low
    807 	 */
    808 	if (how != DMGET) {
    809 		ub = 0;
    810 		/*
    811 		 * need to save current state of DTR & RTS ?
    812 		 */
    813 		if (bits & TIOCM_DTR)
    814 			ub |= 0x04 << unit;
    815 		if (bits & TIOCM_RTS)
    816 			ub |= 0x01 << unit;
    817 	}
    818 	s = splser();
    819 	switch (how) {
    820 	case DMSET:
    821 		sc->sc_regs->du_btst = ub;
    822 		sc->sc_regs->du_btrst = ~ub;
    823 		break;
    824 
    825 	case DMBIC:
    826 		sc->sc_regs->du_btrst = ub;
    827 		ub = ~sc->sc_regs->du_ip;
    828 		break;
    829 
    830 	case DMBIS:
    831 		sc->sc_regs->du_btst = ub;
    832 		ub = ~sc->sc_regs->du_ip;
    833 		break;
    834 
    835 	case DMGET:
    836 		ub = ~sc->sc_regs->du_ip;
    837 		break;
    838 	}
    839 	(void)splx(s);
    840 
    841 	/* XXXX need to keep DTR & RTS states in softc */
    842 	bits = TIOCM_DTR | TIOCM_RTS;
    843 	if (ub & (1 << unit))
    844 		bits |= TIOCM_CTS;
    845 	if (ub & (4 << unit))
    846 		bits |= TIOCM_DSR;
    847 	if (ub & (0x10 << unit))
    848 		bits |= TIOCM_CD;
    849 	if (sc->sc_regs->pad26 & (1 << unit))
    850 		bits |= TIOCM_RI;
    851 
    852 	return(bits);
    853 }
    854 
    855 /*
    856  * Level 6 interrupt processing for the MultiFaceCard 68681 DUART
    857  */
    858 
    859 int
    860 mfcintr (scc)
    861 	struct mfc_softc *scc;
    862 {
    863 	struct mfcs_softc *sc;
    864 	struct mfc_regs *regs;
    865 	struct tty *tp;
    866 	int istat, unit;
    867 	u_short c;
    868 
    869 	regs = scc->sc_regs;
    870 	istat = regs->du_isr & scc->imask;
    871 	if (istat == 0)
    872 		return (0);
    873 	unit = scc->sc_dev.dv_unit * 2;
    874 	if (istat & 0x02) {		/* channel A receive interrupt */
    875 		sc = mfcscd.cd_devs[unit];
    876 		while (1) {
    877 			c = regs->du_sra << 8;
    878 			if ((c & 0x0100) == 0)
    879 				break;
    880 			c |= regs->du_rba;
    881 			if (sc->incnt == SERIBUF_SIZE)
    882 				++sc->ovfl;
    883 			else {
    884 				*sc->wptr++ = c;
    885 				if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
    886 					sc->wptr = sc->inbuf;
    887 				++sc->incnt;
    888 				if (sc->incnt > SERIBUF_SIZE - 16)
    889 					regs->du_btrst = 1;
    890 			}
    891 			if (c & 0x1000)
    892 				regs->du_cra = 0x40;
    893 		}
    894 	}
    895 	if (istat & 0x20) {		/* channel B receive interrupt */
    896 		sc = mfcscd.cd_devs[unit + 1];
    897 		while (1) {
    898 			c = regs->du_srb << 8;
    899 			if ((c & 0x0100) == 0)
    900 				break;
    901 			c |= regs->du_rbb;
    902 			if (sc->incnt == SERIBUF_SIZE)
    903 				++sc->ovfl;
    904 			else {
    905 				*sc->wptr++ = c;
    906 				if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
    907 					sc->wptr = sc->inbuf;
    908 				++sc->incnt;
    909 				if (sc->incnt > SERIBUF_SIZE - 16)
    910 					regs->du_btrst = 2;
    911 			}
    912 			if (c & 0x1000)
    913 				regs->du_crb = 0x40;
    914 		}
    915 	}
    916 	if (istat & 0x01) {		/* channel A transmit interrupt */
    917 		tp = mfcs_tty[unit];
    918 		sc = mfcscd.cd_devs[unit];
    919 		if (sc->ptr == sc->end) {
    920 			tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    921 			scc->imask &= ~0x01;
    922 			regs->du_imr = scc->imask;
    923 			add_sicallback (tp->t_line ?
    924 			    linesw[tp->t_line].l_start : mfcsstart,
    925 			    tp, NULL);
    926 
    927 		}
    928 		else
    929 			regs->du_tba = *sc->ptr++;
    930 	}
    931 	if (istat & 0x10) {		/* channel B transmit interrupt */
    932 		tp = mfcs_tty[unit + 1];
    933 		sc = mfcscd.cd_devs[unit + 1];
    934 		if (sc->ptr == sc->end) {
    935 			tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    936 			scc->imask &= ~0x10;
    937 			regs->du_imr = scc->imask;
    938 			add_sicallback (tp->t_line ?
    939 			    linesw[tp->t_line].l_start : mfcsstart,
    940 			    tp, NULL);
    941 		}
    942 		else
    943 			regs->du_tbb = *sc->ptr++;
    944 	}
    945 	if (istat & 0x80) {		/* input port change interrupt */
    946 		c = regs->du_ipcr;
    947 		printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c);
    948 	}
    949 	return(1);
    950 }
    951 
    952 int
    953 mfcsxintr(unit)
    954 	int unit;
    955 {
    956 	int s1, s2, ovfl;
    957 	struct mfcs_softc *sc = mfcscd.cd_devs[unit];
    958 	struct tty *tp = mfcs_tty[unit];
    959 
    960 	/*
    961 	 * Make sure we're not interrupted by another
    962 	 * vbl, but allow level6 ints
    963 	 */
    964 	s1 = spltty();
    965 
    966 	/*
    967 	 * pass along any acumulated information
    968 	 * while input is not blocked
    969 	 */
    970 	while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) {
    971 		/*
    972 		 * no collision with ser_fastint()
    973 		 */
    974 		mfcseint(unit, *sc->rptr++);
    975 
    976 		ovfl = 0;
    977 		/* lock against mfcs_fastint() */
    978 		s2 = splser();
    979 		--sc->incnt;
    980 		if (sc->rptr == sc->inbuf + SERIBUF_SIZE)
    981 			sc->rptr = sc->inbuf;
    982 		if (sc->ovfl != 0) {
    983 			ovfl = sc->ovfl;
    984 			sc->ovfl = 0;
    985 		}
    986 		splx(s2);
    987 		if (ovfl != 0)
    988 			log(LOG_WARNING, "%s: %d buffer overflow!\n",
    989 			    sc->sc_dev.dv_xname, ovfl);
    990 	}
    991 	if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) {
    992 		sc->sc_regs->du_btst = 1 << unit;	/* XXX */
    993 	}
    994 	splx(s1);
    995 }
    996 
    997 int
    998 mfcseint(unit, stat)
    999 	int unit, stat;
   1000 {
   1001 	struct tty *tp;
   1002 	u_char ch;
   1003 	int c;
   1004 
   1005 	tp = mfcs_tty[unit];
   1006 	ch = stat & 0xff;
   1007 	c = ch;
   1008 
   1009 	if ((tp->t_state & TS_ISOPEN) == 0) {
   1010 #ifdef KGDB
   1011 		/* we don't care about parity errors */
   1012 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
   1013 			kgdb_connect(0);	/* trap into kgdb */
   1014 #endif
   1015 		return;
   1016 	}
   1017 
   1018 	/*
   1019 	 * Check for break and (if enabled) parity error.
   1020 	 */
   1021 	if (stat & 0xc000)
   1022 		c |= TTY_FE;
   1023 	else if (stat & 0x2000)
   1024 			c |= TTY_PE;
   1025 
   1026 	if (stat & 0x1000)
   1027 		log(LOG_WARNING, "%s: fifo overflow\n",
   1028 		    ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname);
   1029 
   1030 	(*linesw[tp->t_line].l_rint)(c, tp);
   1031 }
   1032 
   1033 /*
   1034  * This interrupt is periodically invoked in the vertical blank
   1035  * interrupt.  It's used to keep track of the modem control lines
   1036  * and (new with the fast_int code) to move accumulated data
   1037  * up into the tty layer.
   1038  */
   1039 void
   1040 mfcsmint(unit)
   1041 	int unit;
   1042 {
   1043 	struct tty *tp;
   1044 	struct mfcs_softc *sc = mfcscd.cd_devs[unit];
   1045 	u_char stat, last, istat;
   1046 
   1047 	tp = mfcs_tty[unit];
   1048 	if (!tp)
   1049 		return;
   1050 
   1051 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
   1052 		sc->rptr = sc->wptr = sc->inbuf;
   1053 		sc->incnt = 0;
   1054 		return;
   1055 	}
   1056 	/*
   1057 	 * empty buffer
   1058 	 */
   1059 	mfcsxintr(unit);
   1060 
   1061 	stat = ~sc->sc_regs->du_ip;
   1062 	last = sc->sc_mfc->last_ip;
   1063 	sc->sc_mfc->last_ip = stat;
   1064 
   1065 	/*
   1066 	 * check whether any interesting signal changed state
   1067 	 */
   1068 	istat = stat ^ last;
   1069 
   1070 	if ((istat & (0x10 << (unit & 1))) && 		/* CD changed */
   1071 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
   1072 		if (stat & (0x10 << (unit & 1)))
   1073 			(*linesw[tp->t_line].l_modem)(tp, 1);
   1074 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
   1075 			sc->sc_regs->du_btrst = 0x0a << (unit & 1);
   1076 		}
   1077 	}
   1078 }
   1079