xref: /netbsd-src/sys/arch/amiga/dev/mfc.c (revision 07bae7edddbb1ce4c926b2e8db425804589074c9)
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