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