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