Home | History | Annotate | Line # | Download | only in dev
mfc.c revision 1.3
      1 /*	$NetBSD: mfc.c,v 1.3 1995/03/02 02:23:59 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 + 128];
    211 
    212 struct speedtab mfcs3speedtab[] = {
    213 	0,	0,
    214 	150,	0x00,
    215 	200,	0x11,
    216 	300,	0x33,
    217 	600,	0x44,
    218 	1200,	0x55,
    219 	2400,	0x66,
    220 	4800,	0x88,
    221 	9600,	0x99,
    222 	19200,	0xbb,
    223 	38400,	0xcc,
    224 	-1,	-1
    225 };
    226 
    227 struct speedtab mfcs2speedtab[] = {
    228 	0,	0,
    229 	75,	0x00,
    230 	100,	0x11,
    231 	150,	0x33,
    232 	300,	0x44,
    233 	600,	0x55,
    234 	1200,	0x66,
    235 	2400,	0x88,
    236  	4800,	0x99,
    237 	9600,	0xbb,
    238 	19200,	0xcc,
    239 	-1,	-1
    240 };
    241 
    242 /*
    243  * if we are an bsc/Alf Data MultFaceCard (I, II, and III)
    244  */
    245 int
    246 mfcmatch(pdp, cdp, auxp)
    247 	struct device *pdp;
    248 	struct cfdata *cdp;
    249 	void *auxp;
    250 {
    251 	struct zbus_args *zap;
    252 
    253 	zap = auxp;
    254 	if (zap->manid == 2092 &&
    255 	    (zap->prodid == 16 || zap->prodid == 17 || zap->prodid == 18))
    256 
    257 		return(1);
    258 	return(0);
    259 }
    260 
    261 void
    262 mfcattach(pdp, dp, auxp)
    263 	struct device *pdp, *dp;
    264 	void *auxp;
    265 {
    266 	struct mfc_softc *scc;
    267 	struct zbus_args *zap;
    268 	struct mfc_args ma;
    269 	int unit;
    270 	struct mfc_regs *rp;
    271 
    272 	zap = auxp;
    273 
    274 	printf ("\n");
    275 
    276 	scc = (struct mfc_softc *)dp;
    277 	unit = scc->sc_dev.dv_unit;
    278 	scc->sc_regs = rp = zap->va;
    279 	if (zap->prodid == 18)
    280 		scc->mfc_iii = 3;
    281 	scc->clk_frq = scc->mfc_iii ? 230400 : 115200;
    282 
    283 	rp->du_opcr = 0x00;		/* configure output port? */
    284 	rp->du_btrst = 0x0f;		/* clear modem lines */
    285 	rp->du_ivr = 0;			/* IVR */
    286 	rp->du_imr = 0;			/* IMR */
    287 	rp->du_acr = 0xe0;		/* baud rate generate set 2 */
    288 	rp->du_ctur = 0;
    289 	rp->du_ctlr = 4;
    290 	rp->du_csra = 0xcc;		/* clock select = 38400 */
    291 	rp->du_cra = 0x10;		/* reset mode register ptr */
    292 	rp->du_cra = 0x20;
    293 	rp->du_cra = 0x30;
    294 	rp->du_cra = 0x40;
    295 	rp->du_mr1a = 0x93;		/* MRA1 */
    296 	rp->du_mr2a = 0x17;		/* MRA2 */
    297 	rp->du_csrb = 0xcc;		/* clock select = 38400 */
    298 	rp->du_crb = 0x10;		/* reset mode register ptr */
    299 	rp->du_crb = 0x20;
    300 	rp->du_crb = 0x30;
    301 	rp->du_crb = 0x40;
    302 	rp->du_mr1b = 0x93;		/* MRB1 */
    303 	rp->du_mr2b = 0x17;		/* MRB2 */
    304 	rp->du_cra = 0x05;		/* enable A Rx & Tx */
    305 	rp->du_crb = 0x05;		/* enable B Rx & Tx */
    306 
    307 	scc->sc_isr.isr_intr = mfcintr;
    308 	scc->sc_isr.isr_arg = scc;
    309 	scc->sc_isr.isr_ipl = 6;
    310 	add_isr(&scc->sc_isr);
    311 
    312 	/* configure ports */
    313 	bcopy(zap, &ma.zargs, sizeof(struct zbus_args));
    314 	ma.subdev = "mfcs";
    315 	ma.unit = unit * 2;
    316 	config_found(dp, &ma, mfcprint);
    317 	ma.unit = unit * 2 + 1;
    318 	config_found(dp, &ma, mfcprint);
    319 	ma.subdev = "mfcp";
    320 	ma.unit = unit;
    321 	config_found(dp, &ma, mfcprint);
    322 }
    323 
    324 /*
    325  *
    326  */
    327 int
    328 mfcsmatch(pdp, cdp, auxp)
    329 	struct device *pdp;
    330 	struct cfdata *cdp;
    331 	void *auxp;
    332 {
    333 	struct mfc_args *ma;
    334 
    335 	ma = auxp;
    336 	if (strcmp(ma->subdev, "mfcs") == 0)
    337 		return (1);
    338 	return (0);
    339 }
    340 
    341 void
    342 mfcsattach(pdp, dp, auxp)
    343 	struct device *pdp, *dp;
    344 	void *auxp;
    345 {
    346 	int unit;
    347 	struct mfcs_softc *sc;
    348 	struct mfc_softc *scc;
    349 	struct mfc_args *ma;
    350 	struct mfc_regs *rp;
    351 
    352 	sc = (struct mfcs_softc *) dp;
    353 	scc = (struct mfc_softc *) pdp;
    354 	ma = auxp;
    355 
    356 	if (dp) {
    357 		printf (": input fifo %d output fifo %d\n", SERIBUF_SIZE,
    358 		    SEROBUF_SIZE);
    359 		alloc_sicallback();
    360 	}
    361 
    362 	unit = ma->unit;
    363 	mfcs_active |= 1 << unit;
    364 	sc->rptr = sc->wptr = sc->inbuf;
    365 	sc->sc_mfc = scc;
    366 	sc->sc_regs = rp = scc->sc_regs;
    367 	sc->sc_duart = (struct duart_regs *) ((unit & 1) ? &rp->du_mr1b :
    368 	    &rp->du_mr1a);
    369 	/*
    370 	 * should have only one vbl routine to handle all ports?
    371 	 */
    372 	mfcs_vbl_node[unit].function = (void (*) (void *)) mfcsmint;
    373 	mfcs_vbl_node[unit].data = (void *) unit;
    374 	add_vbl_function(&mfcs_vbl_node[unit], 1, (void *) unit);
    375 }
    376 
    377 /*
    378  * print diag if pnp is NULL else just extra
    379  */
    380 int
    381 mfcprint(auxp, pnp)
    382 	void *auxp;
    383 	char *pnp;
    384 {
    385 	if (pnp == NULL)
    386 		return(UNCONF);
    387 	return(QUIET);
    388 }
    389 
    390 int
    391 mfcsopen(dev, flag, mode, p)
    392 	dev_t dev;
    393 	int flag, mode;
    394 	struct proc *p;
    395 {
    396 	struct tty *tp;
    397 	int unit, error, s;
    398 
    399 	error = 0;
    400 	unit = dev & 0x1f;
    401 
    402 	if (unit >= NMFCS || (mfcs_active & (1 << unit)) == 0)
    403 		return (ENXIO);
    404 
    405 	s = spltty();
    406 
    407 	if (mfcs_tty[unit])
    408 		tp = mfcs_tty[unit];
    409 	else
    410 		tp = mfcs_tty[unit] = mfcs_tty[unit + 128] = ttymalloc();
    411 
    412 	tp->t_oproc = (void (*) (struct tty *)) mfcsstart;
    413 	tp->t_param = mfcsparam;
    414 	tp->t_dev = dev;
    415 	tp->t_hwiflow = mfcshwiflow;
    416 
    417 	if ((tp->t_state & TS_ISOPEN) == 0) {
    418 		tp->t_state |= TS_WOPEN;
    419 		ttychars(tp);
    420 		if (tp->t_ispeed == 0) {
    421 			/*
    422 			 * only when cleared do we reset to defaults.
    423 			 */
    424 			tp->t_iflag = TTYDEF_IFLAG;
    425 			tp->t_oflag = TTYDEF_OFLAG;
    426 			tp->t_cflag = TTYDEF_CFLAG;
    427 			tp->t_lflag = TTYDEF_LFLAG;
    428 			tp->t_ispeed = tp->t_ospeed = mfcsdefaultrate;
    429 		}
    430 		/*
    431 		 * do these all the time
    432 		 */
    433 		if (mfcsswflags[unit] & TIOCFLAG_CLOCAL)
    434 			tp->t_cflag |= CLOCAL;
    435 		if (mfcsswflags[unit] & TIOCFLAG_CRTSCTS)
    436 			tp->t_cflag |= CRTSCTS;
    437 		if (mfcsswflags[unit] & TIOCFLAG_MDMBUF)
    438 			tp->t_cflag |= MDMBUF;
    439 		mfcsparam(tp, &tp->t_termios);
    440 		ttsetwater(tp);
    441 
    442 		(void)mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    443 		if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
    444 		    (mfcsmctl(dev, 0, DMGET) & TIOCM_CD))
    445 			tp->t_state |= TS_CARR_ON;
    446 		else
    447 			tp->t_state &= ~TS_CARR_ON;
    448 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
    449 		splx(s);
    450 		return(EBUSY);
    451 	}
    452 
    453 	/*
    454 	 * if NONBLOCK requested, ignore carrier
    455 	 */
    456 	if (flag & O_NONBLOCK)
    457 		goto done;
    458 
    459 	/*
    460 	 * block waiting for carrier
    461 	 */
    462 	while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
    463 		tp->t_state |= TS_WOPEN;
    464 		error = ttysleep(tp, (caddr_t)&tp->t_rawq,
    465 		    TTIPRI | PCATCH, ttopen, 0);
    466 		if (error) {
    467 			splx(s);
    468 			return(error);
    469 		}
    470 	}
    471 done:
    472 	/* This is a way to handle lost XON characters */
    473 	if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
    474 		tp->t_state &= ~TS_TTSTOP;
    475 	        ttstart (tp);
    476 	}
    477 
    478 	splx(s);
    479 	/*
    480 	 * Reset the tty pointer, as there could have been a dialout
    481 	 * use of the tty with a dialin open waiting.
    482 	 */
    483 	tp->t_dev = dev;
    484 	return((*linesw[tp->t_line].l_open)(dev, tp));
    485 }
    486 
    487 /*ARGSUSED*/
    488 int
    489 mfcsclose(dev, flag, mode, p)
    490 	dev_t dev;
    491 	int flag, mode;
    492 	struct proc *p;
    493 {
    494 	struct tty *tp;
    495 	int unit;
    496 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
    497 	struct mfc_softc *scc= sc->sc_mfc;
    498 
    499 	unit = dev & 31;
    500 
    501 	tp = mfcs_tty[unit];
    502 	(*linesw[tp->t_line].l_close)(tp, flag);
    503 	sc->sc_duart->ch_cr = 0x70;			/* stop break */
    504 
    505 	scc->imask &= ~(0x7 << ((unit & 1) * 4));
    506 	scc->sc_regs->du_imr = scc->imask;
    507 	if (sc->flags & CT_USED) {
    508 		--scc->ct_usecnt;
    509 		sc->flags &= ~CT_USED;
    510 	}
    511 
    512 	/*
    513 	 * If the device is closed, it's close, no matter whether we deal with
    514 	 * modem control signals nor not.
    515 	 */
    516 #if 0
    517 	if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
    518 	    (tp->t_state & TS_ISOPEN) == 0)
    519 #endif
    520 		(void) mfcsmctl(dev, 0, DMSET);
    521 	ttyclose(tp);
    522 #if not_yet
    523 	if (tp != &mfcs_cons) {
    524 		remove_vbl_function(&mfcs_vbl_node[unit]);
    525 		ttyfree(tp);
    526 		mfcs_tty[unit] = (struct tty *) NULL;
    527 	}
    528 #endif
    529 	return (0);
    530 }
    531 
    532 int
    533 mfcsread(dev, uio, flag)
    534 	dev_t dev;
    535 	struct uio *uio;
    536 	int flag;
    537 {
    538 	struct tty *tp;
    539 	if ((tp = mfcs_tty[dev & 31]) == NULL)
    540 		return(ENXIO);
    541 	return((*linesw[tp->t_line].l_read)(tp, uio, flag));
    542 }
    543 
    544 int
    545 mfcswrite(dev, uio, flag)
    546 	dev_t dev;
    547 	struct uio *uio;
    548 	int flag;
    549 {
    550 	struct tty *tp;
    551 
    552 	if ((tp = mfcs_tty[dev & 31]) == NULL)
    553 		return(ENXIO);
    554 	return((*linesw[tp->t_line].l_write)(tp, uio, flag));
    555 }
    556 int
    557 mfcsioctl(dev, cmd, data, flag, p)
    558 	dev_t	dev;
    559 	caddr_t data;
    560 	struct proc *p;
    561 {
    562 	register struct tty *tp;
    563 	register int unit = dev & 31;
    564 	register int error;
    565 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
    566 
    567 	tp = mfcs_tty[unit];
    568 	if (!tp)
    569 		return ENXIO;
    570 
    571 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    572 	if (error >= 0)
    573 		return(error);
    574 
    575 	error = ttioctl(tp, cmd, data, flag, p);
    576 	if (error >= 0)
    577 		return(error);
    578 
    579 	switch (cmd) {
    580 	case TIOCSBRK:
    581 		sc->sc_duart->ch_cr = 0x60;		/* start break */
    582 		break;
    583 
    584 	case TIOCCBRK:
    585 		sc->sc_duart->ch_cr = 0x70;		/* stop break */
    586 		break;
    587 
    588 	case TIOCSDTR:
    589 		(void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    590 		break;
    591 
    592 	case TIOCCDTR:
    593 		(void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    594 		break;
    595 
    596 	case TIOCMSET:
    597 		(void) mfcsmctl(dev, *(int *) data, DMSET);
    598 		break;
    599 
    600 	case TIOCMBIS:
    601 		(void) mfcsmctl(dev, *(int *) data, DMBIS);
    602 		break;
    603 
    604 	case TIOCMBIC:
    605 		(void) mfcsmctl(dev, *(int *) data, DMBIC);
    606 		break;
    607 
    608 	case TIOCMGET:
    609 		*(int *)data = mfcsmctl(dev, 0, DMGET);
    610 		break;
    611 	case TIOCGFLAGS:
    612 		*(int *)data = SWFLAGS(dev);
    613 		break;
    614 	case TIOCSFLAGS:
    615 		error = suser(p->p_ucred, &p->p_acflag);
    616 		if (error != 0)
    617 			return(EPERM);
    618 
    619 		mfcsswflags[unit] = *(int *)data;
    620                 mfcsswflags[unit] &= /* only allow valid flags */
    621                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
    622 		/* XXXX need to change duart parameters!! */
    623 		break;
    624 	default:
    625 		return(ENOTTY);
    626 	}
    627 
    628 	return(0);
    629 }
    630 
    631 int
    632 mfcsparam(tp, t)
    633 	struct tty *tp;
    634 	struct termios *t;
    635 {
    636 	int cfcr, cflag, unit, ospeed;
    637 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
    638 	struct mfc_softc *scc= sc->sc_mfc;
    639 
    640 	cflag = t->c_cflag;
    641 	unit = tp->t_dev & 31;
    642 	if (sc->flags & CT_USED) {
    643 		--scc->ct_usecnt;
    644 		sc->flags &= ~CT_USED;
    645 	}
    646 	ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab :
    647 	    mfcs2speedtab);
    648 
    649 	/*
    650 	 * If Baud Rate Generator can't generate requested speed,
    651 	 * try to use the counter/timer.
    652 	 */
    653 	if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) {
    654 		ospeed = scc->clk_frq / t->c_ospeed;	/* divisor */
    655 		if (scc->ct_usecnt > 0 && scc->ct_val != ospeed)
    656 			ospeed = -1;
    657 		else {
    658 			scc->sc_regs->du_ctur = ospeed >> 8;
    659 			scc->sc_regs->du_ctlr = ospeed;
    660 			scc->ct_val = ospeed;
    661 			++scc->ct_usecnt;
    662 			sc->flags |= CT_USED;
    663 			ospeed = 0xdd;
    664 		}
    665 	}
    666 	/* XXXX 68681 duart could handle split speeds */
    667 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    668 		return(EINVAL);
    669 
    670 	/*
    671 	 * copy to tty
    672 	 */
    673 	tp->t_ispeed = t->c_ispeed;
    674 	tp->t_ospeed = t->c_ospeed;
    675 	tp->t_cflag = cflag;
    676 
    677 	/*
    678 	 * enable interrupts
    679 	 */
    680 	scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80;
    681 	scc->sc_regs->du_imr = scc->imask;
    682 #if defined(DEBUG) && 0
    683 	printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n",
    684 	    t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag);
    685 #endif
    686 	if (ospeed == 0)
    687 		(void)mfcsmctl(tp->t_dev, 0, DMSET);	/* hang up line */
    688 	else {
    689 		/*
    690 		 * (re)enable DTR
    691 		 * and set baud rate. (8 bit mode)
    692 		 */
    693 		(void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    694 		sc->sc_duart->ch_csr = ospeed;
    695 	}
    696 	return(0);
    697 }
    698 
    699 int mfcshwiflow(tp, flag)
    700         struct tty *tp;
    701         int flag;
    702 {
    703 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
    704 	int unit = tp->t_dev & 1;
    705 
    706         if (flag)
    707 		sc->sc_regs->du_btrst = 1 << unit;
    708 	else
    709 		sc->sc_regs->du_btst = 1 << unit;
    710         return 1;
    711 }
    712 
    713 int
    714 mfcsstart(tp)
    715 	struct tty *tp;
    716 {
    717 	int cc, s, unit;
    718 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
    719 	struct mfc_softc *scc= sc->sc_mfc;
    720 
    721 	if ((tp->t_state & TS_ISOPEN) == 0)
    722 		return;
    723 
    724 	unit = tp->t_dev & 1;
    725 
    726 	s = splser();
    727 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
    728 		goto out;
    729 
    730 	cc = tp->t_outq.c_cc;
    731 	if (cc <= tp->t_lowat) {
    732 		if (tp->t_state & TS_ASLEEP) {
    733 			tp->t_state &= ~TS_ASLEEP;
    734 			wakeup((caddr_t) & tp->t_outq);
    735 		}
    736 		selwakeup(&tp->t_wsel);
    737 	}
    738 	if (cc == 0 || (tp->t_state & TS_BUSY))
    739 		goto out;
    740 
    741 	/*
    742 	 * We only do bulk transfers if using CTSRTS flow control, not for
    743 	 * (probably sloooow) ixon/ixoff devices.
    744 	 */
    745 	if ((tp->t_cflag & CRTSCTS) == 0)
    746 		cc = 1;
    747 
    748 	/*
    749 	 * Limit the amount of output we do in one burst
    750 	 * to prevent hogging the CPU.
    751 	 */
    752 	if (cc > SEROBUF_SIZE)
    753 		cc = SEROBUF_SIZE;
    754 	cc = q_to_b(&tp->t_outq, sc->outbuf, cc);
    755 	if (cc > 0) {
    756 		tp->t_state |= TS_BUSY;
    757 
    758 		sc->ptr = sc->outbuf;
    759 		sc->end = sc->outbuf + cc;
    760 
    761 		/*
    762 		 * Get first character out, then have TBE-interrupts blow out
    763 		 * further characters, until buffer is empty, and TS_BUSY gets
    764 		 * cleared.
    765 		 */
    766 		sc->sc_duart->ch_tb = *sc->ptr++;
    767 		scc->imask |= 1 << (unit * 4);
    768 		sc->sc_regs->du_imr = scc->imask;
    769 	}
    770 out:
    771 	splx(s);
    772 }
    773 
    774 /*
    775  * Stop output on a line.
    776  */
    777 /*ARGSUSED*/
    778 int
    779 mfcsstop(tp, flag)
    780 	struct tty *tp;
    781 {
    782 	int s;
    783 
    784 	s = splser();
    785 	if (tp->t_state & TS_BUSY) {
    786 		if ((tp->t_state & TS_TTSTOP) == 0)
    787 			tp->t_state |= TS_FLUSH;
    788 	}
    789 	splx(s);
    790 }
    791 
    792 int
    793 mfcsmctl(dev, bits, how)
    794 	dev_t dev;
    795 	int bits, how;
    796 {
    797 	int unit, s;
    798 	u_char ub;
    799 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
    800 
    801 	unit = dev & 1;
    802 
    803 	/*
    804 	 * convert TIOCM* mask into CIA mask
    805 	 * which is active low
    806 	 */
    807 	if (how != DMGET) {
    808 		ub = 0;
    809 		/*
    810 		 * need to save current state of DTR & RTS ?
    811 		 */
    812 		if (bits & TIOCM_DTR)
    813 			ub |= 0x04 << unit;
    814 		if (bits & TIOCM_RTS)
    815 			ub |= 0x01 << unit;
    816 	}
    817 	s = splser();
    818 	switch (how) {
    819 	case DMSET:
    820 		sc->sc_regs->du_btst = ub;
    821 		sc->sc_regs->du_btrst = ~ub;
    822 		break;
    823 
    824 	case DMBIC:
    825 		sc->sc_regs->du_btrst = ub;
    826 		ub = ~sc->sc_regs->du_ip;
    827 		break;
    828 
    829 	case DMBIS:
    830 		sc->sc_regs->du_btst = ub;
    831 		ub = ~sc->sc_regs->du_ip;
    832 		break;
    833 
    834 	case DMGET:
    835 		ub = ~sc->sc_regs->du_ip;
    836 		break;
    837 	}
    838 	(void)splx(s);
    839 
    840 	/* XXXX need to keep DTR & RTS states in softc */
    841 	bits = TIOCM_DTR | TIOCM_RTS;
    842 	if (ub & (1 << unit))
    843 		bits |= TIOCM_CTS;
    844 	if (ub & (4 << unit))
    845 		bits |= TIOCM_DSR;
    846 	if (ub & (0x10 << unit))
    847 		bits |= TIOCM_CD;
    848 	if (sc->sc_regs->pad26 & (1 << unit))
    849 		bits |= TIOCM_RI;
    850 
    851 	return(bits);
    852 }
    853 
    854 /*
    855  * Level 6 interrupt processing for the MultiFaceCard 68681 DUART
    856  */
    857 
    858 int
    859 mfcintr (scc)
    860 	struct mfc_softc *scc;
    861 {
    862 	struct mfcs_softc *sc;
    863 	struct mfc_regs *regs;
    864 	struct tty *tp;
    865 	int istat, unit;
    866 	u_short c;
    867 
    868 	regs = scc->sc_regs;
    869 	istat = regs->du_isr & scc->imask;
    870 	if (istat == 0)
    871 		return (0);
    872 	unit = scc->sc_dev.dv_unit * 2;
    873 	if (istat & 0x02) {		/* channel A receive interrupt */
    874 		sc = mfcscd.cd_devs[unit];
    875 		while (1) {
    876 			c = regs->du_sra << 8;
    877 			if ((c & 0x0100) == 0)
    878 				break;
    879 			c |= regs->du_rba;
    880 			if (sc->incnt == SERIBUF_SIZE)
    881 				++sc->ovfl;
    882 			else {
    883 				*sc->wptr++ = c;
    884 				if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
    885 					sc->wptr = sc->inbuf;
    886 				++sc->incnt;
    887 				if (sc->incnt > SERIBUF_SIZE - 16)
    888 					regs->du_btrst = 1;
    889 			}
    890 			if (c & 0x1000)
    891 				regs->du_cra = 0x40;
    892 		}
    893 	}
    894 	if (istat & 0x20) {		/* channel B receive interrupt */
    895 		sc = mfcscd.cd_devs[unit + 1];
    896 		while (1) {
    897 			c = regs->du_srb << 8;
    898 			if ((c & 0x0100) == 0)
    899 				break;
    900 			c |= regs->du_rbb;
    901 			if (sc->incnt == SERIBUF_SIZE)
    902 				++sc->ovfl;
    903 			else {
    904 				*sc->wptr++ = c;
    905 				if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
    906 					sc->wptr = sc->inbuf;
    907 				++sc->incnt;
    908 				if (sc->incnt > SERIBUF_SIZE - 16)
    909 					regs->du_btrst = 2;
    910 			}
    911 			if (c & 0x1000)
    912 				regs->du_crb = 0x40;
    913 		}
    914 	}
    915 	if (istat & 0x01) {		/* channel A transmit interrupt */
    916 		tp = mfcs_tty[unit];
    917 		sc = mfcscd.cd_devs[unit];
    918 		if (sc->ptr == sc->end) {
    919 			tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    920 			scc->imask &= ~0x01;
    921 			regs->du_imr = scc->imask;
    922 			add_sicallback (tp->t_line ?
    923 			    linesw[tp->t_line].l_start : mfcsstart,
    924 			    tp, NULL);
    925 
    926 		}
    927 		else
    928 			regs->du_tba = *sc->ptr++;
    929 	}
    930 	if (istat & 0x10) {		/* channel B transmit interrupt */
    931 		tp = mfcs_tty[unit + 1];
    932 		sc = mfcscd.cd_devs[unit + 1];
    933 		if (sc->ptr == sc->end) {
    934 			tp->t_state &= ~(TS_BUSY | TS_FLUSH);
    935 			scc->imask &= ~0x10;
    936 			regs->du_imr = scc->imask;
    937 			add_sicallback (tp->t_line ?
    938 			    linesw[tp->t_line].l_start : mfcsstart,
    939 			    tp, NULL);
    940 		}
    941 		else
    942 			regs->du_tbb = *sc->ptr++;
    943 	}
    944 	if (istat & 0x80) {		/* input port change interrupt */
    945 		c = regs->du_ipcr;
    946 		printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c);
    947 	}
    948 	return(1);
    949 }
    950 
    951 int
    952 mfcsxintr(unit)
    953 	int unit;
    954 {
    955 	int s1, s2, ovfl;
    956 	struct mfcs_softc *sc = mfcscd.cd_devs[unit];
    957 	struct tty *tp = mfcs_tty[unit];
    958 
    959 	/*
    960 	 * Make sure we're not interrupted by another
    961 	 * vbl, but allow level6 ints
    962 	 */
    963 	s1 = spltty();
    964 
    965 	/*
    966 	 * pass along any acumulated information
    967 	 * while input is not blocked
    968 	 */
    969 	while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) {
    970 		/*
    971 		 * no collision with ser_fastint()
    972 		 */
    973 		mfcseint(unit, *sc->rptr++);
    974 
    975 		ovfl = 0;
    976 		/* lock against mfcs_fastint() */
    977 		s2 = splser();
    978 		--sc->incnt;
    979 		if (sc->rptr == sc->inbuf + SERIBUF_SIZE)
    980 			sc->rptr = sc->inbuf;
    981 		if (sc->ovfl != 0) {
    982 			ovfl = sc->ovfl;
    983 			sc->ovfl = 0;
    984 		}
    985 		splx(s2);
    986 		if (ovfl != 0)
    987 			log(LOG_WARNING, "%s: %d buffer overflow!\n",
    988 			    sc->sc_dev.dv_xname, ovfl);
    989 	}
    990 	if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) {
    991 		sc->sc_regs->du_btst = 1 << unit;	/* XXX */
    992 	}
    993 	splx(s1);
    994 }
    995 
    996 int
    997 mfcseint(unit, stat)
    998 	int unit, stat;
    999 {
   1000 	struct tty *tp;
   1001 	u_char ch;
   1002 	int c;
   1003 
   1004 	tp = mfcs_tty[unit];
   1005 	ch = stat & 0xff;
   1006 	c = ch;
   1007 
   1008 	if ((tp->t_state & TS_ISOPEN) == 0) {
   1009 #ifdef KGDB
   1010 		/* we don't care about parity errors */
   1011 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
   1012 			kgdb_connect(0);	/* trap into kgdb */
   1013 #endif
   1014 		return;
   1015 	}
   1016 
   1017 	/*
   1018 	 * Check for break and (if enabled) parity error.
   1019 	 */
   1020 	if (stat & 0xc000)
   1021 		c |= TTY_FE;
   1022 	else if (stat & 0x2000)
   1023 			c |= TTY_PE;
   1024 
   1025 	if (stat & 0x1000)
   1026 		log(LOG_WARNING, "%s: fifo overflow\n",
   1027 		    ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname);
   1028 
   1029 	(*linesw[tp->t_line].l_rint)(c, tp);
   1030 }
   1031 
   1032 /*
   1033  * This interrupt is periodically invoked in the vertical blank
   1034  * interrupt.  It's used to keep track of the modem control lines
   1035  * and (new with the fast_int code) to move accumulated data
   1036  * up into the tty layer.
   1037  */
   1038 void
   1039 mfcsmint(unit)
   1040 	int unit;
   1041 {
   1042 	struct tty *tp;
   1043 	struct mfcs_softc *sc = mfcscd.cd_devs[unit];
   1044 	u_char stat, last, istat;
   1045 
   1046 	tp = mfcs_tty[unit];
   1047 	if (!tp)
   1048 		return;
   1049 
   1050 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
   1051 		sc->rptr = sc->wptr = sc->inbuf;
   1052 		sc->incnt = 0;
   1053 		return;
   1054 	}
   1055 	/*
   1056 	 * empty buffer
   1057 	 */
   1058 	mfcsxintr(unit);
   1059 
   1060 	stat = ~sc->sc_regs->du_ip;
   1061 	last = sc->sc_mfc->last_ip;
   1062 	sc->sc_mfc->last_ip = stat;
   1063 
   1064 	/*
   1065 	 * check whether any interesting signal changed state
   1066 	 */
   1067 	istat = stat ^ last;
   1068 
   1069 	if ((istat & (0x10 << (unit & 1))) && 		/* CD changed */
   1070 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
   1071 		if (stat & (0x10 << (unit & 1)))
   1072 			(*linesw[tp->t_line].l_modem)(tp, 1);
   1073 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
   1074 			sc->sc_regs->du_btrst = 0x0a << (unit & 1);
   1075 		}
   1076 	}
   1077 }
   1078