xref: /netbsd-src/sys/arch/amiga/dev/mfc.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: mfc.c,v 1.4 1995/04/02 20:38:49 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 #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] = mfcs_tty[unit + 128] = 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 int
609 mfcsioctl(dev, cmd, data, flag, p)
610 	dev_t	dev;
611 	caddr_t data;
612 	struct proc *p;
613 {
614 	register struct tty *tp;
615 	register int unit = dev & 31;
616 	register int error;
617 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
618 
619 	tp = mfcs_tty[unit];
620 	if (!tp)
621 		return ENXIO;
622 
623 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
624 	if (error >= 0)
625 		return(error);
626 
627 	error = ttioctl(tp, cmd, data, flag, p);
628 	if (error >= 0)
629 		return(error);
630 
631 	switch (cmd) {
632 	case TIOCSBRK:
633 		sc->sc_duart->ch_cr = 0x60;		/* start break */
634 		break;
635 
636 	case TIOCCBRK:
637 		sc->sc_duart->ch_cr = 0x70;		/* stop break */
638 		break;
639 
640 	case TIOCSDTR:
641 		(void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
642 		break;
643 
644 	case TIOCCDTR:
645 		(void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
646 		break;
647 
648 	case TIOCMSET:
649 		(void) mfcsmctl(dev, *(int *) data, DMSET);
650 		break;
651 
652 	case TIOCMBIS:
653 		(void) mfcsmctl(dev, *(int *) data, DMBIS);
654 		break;
655 
656 	case TIOCMBIC:
657 		(void) mfcsmctl(dev, *(int *) data, DMBIC);
658 		break;
659 
660 	case TIOCMGET:
661 		*(int *)data = mfcsmctl(dev, 0, DMGET);
662 		break;
663 	case TIOCGFLAGS:
664 		*(int *)data = SWFLAGS(dev);
665 		break;
666 	case TIOCSFLAGS:
667 		error = suser(p->p_ucred, &p->p_acflag);
668 		if (error != 0)
669 			return(EPERM);
670 
671 		mfcsswflags[unit] = *(int *)data;
672                 mfcsswflags[unit] &= /* only allow valid flags */
673                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
674 		/* XXXX need to change duart parameters? */
675 		break;
676 	default:
677 		return(ENOTTY);
678 	}
679 
680 	return(0);
681 }
682 
683 int
684 mfcsparam(tp, t)
685 	struct tty *tp;
686 	struct termios *t;
687 {
688 	int cfcr, cflag, unit, ospeed;
689 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
690 	struct mfc_softc *scc= sc->sc_mfc;
691 
692 	cflag = t->c_cflag;
693 	unit = tp->t_dev & 31;
694 	if (sc->flags & CT_USED) {
695 		--scc->ct_usecnt;
696 		sc->flags &= ~CT_USED;
697 	}
698 	ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab2 :
699 	    mfcs2speedtab2);
700 
701 	/*
702 	 * If Baud Rate Generator can't generate requested speed,
703 	 * try to use the counter/timer.
704 	 */
705 	if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) {
706 		ospeed = scc->clk_frq / t->c_ospeed;	/* divisor */
707 		if (scc->ct_usecnt > 0 && scc->ct_val != ospeed)
708 			ospeed = -1;
709 		else {
710 			scc->sc_regs->du_ctur = ospeed >> 8;
711 			scc->sc_regs->du_ctlr = ospeed;
712 			scc->ct_val = ospeed;
713 			++scc->ct_usecnt;
714 			sc->flags |= CT_USED;
715 			ospeed = 0xdd;
716 		}
717 	}
718 	/* XXXX 68681 duart could handle split speeds */
719 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
720 		return(EINVAL);
721 
722 	/* XXXX handle parity, character size, stop bits, flow control */
723 
724 	/*
725 	 * copy to tty
726 	 */
727 	tp->t_ispeed = t->c_ispeed;
728 	tp->t_ospeed = t->c_ospeed;
729 	tp->t_cflag = cflag;
730 
731 	/*
732 	 * enable interrupts
733 	 */
734 	scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80;
735 	scc->sc_regs->du_imr = scc->imask;
736 #if defined(DEBUG) && 0
737 	printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n",
738 	    t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag);
739 #endif
740 	if (ospeed == 0)
741 		(void)mfcsmctl(tp->t_dev, 0, DMSET);	/* hang up line */
742 	else {
743 		/*
744 		 * (re)enable DTR
745 		 * and set baud rate. (8 bit mode)
746 		 */
747 		(void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
748 		sc->sc_duart->ch_csr = ospeed;
749 	}
750 	return(0);
751 }
752 
753 int mfcshwiflow(tp, flag)
754         struct tty *tp;
755         int flag;
756 {
757 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
758 	int unit = tp->t_dev & 1;
759 
760         if (flag)
761 		sc->sc_regs->du_btrst = 1 << unit;
762 	else
763 		sc->sc_regs->du_btst = 1 << unit;
764         return 1;
765 }
766 
767 int
768 mfcsstart(tp)
769 	struct tty *tp;
770 {
771 	int cc, s, unit;
772 	struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
773 	struct mfc_softc *scc= sc->sc_mfc;
774 
775 	if ((tp->t_state & TS_ISOPEN) == 0)
776 		return;
777 
778 	unit = tp->t_dev & 1;
779 
780 	s = splser();
781 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
782 		goto out;
783 
784 	cc = tp->t_outq.c_cc;
785 	if (cc <= tp->t_lowat) {
786 		if (tp->t_state & TS_ASLEEP) {
787 			tp->t_state &= ~TS_ASLEEP;
788 			wakeup((caddr_t) & tp->t_outq);
789 		}
790 		selwakeup(&tp->t_wsel);
791 	}
792 	if (cc == 0 || (tp->t_state & TS_BUSY))
793 		goto out;
794 
795 	/*
796 	 * We only do bulk transfers if using CTSRTS flow control, not for
797 	 * (probably sloooow) ixon/ixoff devices.
798 	 */
799 	if ((tp->t_cflag & CRTSCTS) == 0)
800 		cc = 1;
801 
802 	/*
803 	 * Limit the amount of output we do in one burst
804 	 * to prevent hogging the CPU.
805 	 */
806 	if (cc > SEROBUF_SIZE)
807 		cc = SEROBUF_SIZE;
808 	cc = q_to_b(&tp->t_outq, sc->outbuf, cc);
809 	if (cc > 0) {
810 		tp->t_state |= TS_BUSY;
811 
812 		sc->ptr = sc->outbuf;
813 		sc->end = sc->outbuf + cc;
814 
815 		/*
816 		 * Get first character out, then have TBE-interrupts blow out
817 		 * further characters, until buffer is empty, and TS_BUSY gets
818 		 * cleared.
819 		 */
820 		sc->sc_duart->ch_tb = *sc->ptr++;
821 		scc->imask |= 1 << (unit * 4);
822 		sc->sc_regs->du_imr = scc->imask;
823 	}
824 out:
825 	splx(s);
826 }
827 
828 /*
829  * Stop output on a line.
830  */
831 /*ARGSUSED*/
832 int
833 mfcsstop(tp, flag)
834 	struct tty *tp;
835 {
836 	int s;
837 
838 	s = splser();
839 	if (tp->t_state & TS_BUSY) {
840 		if ((tp->t_state & TS_TTSTOP) == 0)
841 			tp->t_state |= TS_FLUSH;
842 	}
843 	splx(s);
844 }
845 
846 int
847 mfcsmctl(dev, bits, how)
848 	dev_t dev;
849 	int bits, how;
850 {
851 	int unit, s;
852 	u_char ub;
853 	struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
854 
855 	unit = dev & 1;
856 
857 	/*
858 	 * convert TIOCM* mask into CIA mask
859 	 * which is active low
860 	 */
861 	if (how != DMGET) {
862 		ub = 0;
863 		/*
864 		 * need to save current state of DTR & RTS ?
865 		 */
866 		if (bits & TIOCM_DTR)
867 			ub |= 0x04 << unit;
868 		if (bits & TIOCM_RTS)
869 			ub |= 0x01 << unit;
870 	}
871 	s = splser();
872 	switch (how) {
873 	case DMSET:
874 		sc->sc_regs->du_btst = ub;
875 		sc->sc_regs->du_btrst = ub ^ (0x05 << unit);
876 		break;
877 
878 	case DMBIC:
879 		sc->sc_regs->du_btrst = ub;
880 		ub = ~sc->sc_regs->du_ip;
881 		break;
882 
883 	case DMBIS:
884 		sc->sc_regs->du_btst = ub;
885 		ub = ~sc->sc_regs->du_ip;
886 		break;
887 
888 	case DMGET:
889 		ub = ~sc->sc_regs->du_ip;
890 		break;
891 	}
892 	(void)splx(s);
893 
894 	/* XXXX should keep DTR & RTS states in softc? */
895 	bits = TIOCM_DTR | TIOCM_RTS;
896 	if (ub & (1 << unit))
897 		bits |= TIOCM_CTS;
898 	if (ub & (4 << unit))
899 		bits |= TIOCM_DSR;
900 	if (ub & (0x10 << unit))
901 		bits |= TIOCM_CD;
902 	/* XXXX RI is not supported on all boards */
903 	if (sc->sc_regs->pad26 & (1 << unit))
904 		bits |= TIOCM_RI;
905 
906 	return(bits);
907 }
908 
909 /*
910  * Level 6 interrupt processing for the MultiFaceCard 68681 DUART
911  */
912 
913 int
914 mfcintr (scc)
915 	struct mfc_softc *scc;
916 {
917 	struct mfcs_softc *sc;
918 	struct mfc_regs *regs;
919 	struct tty *tp;
920 	int istat, unit;
921 	u_short c;
922 
923 	regs = scc->sc_regs;
924 	istat = regs->du_isr & scc->imask;
925 	if (istat == 0)
926 		return (0);
927 	unit = scc->sc_dev.dv_unit * 2;
928 	if (istat & 0x02) {		/* channel A receive interrupt */
929 		sc = mfcscd.cd_devs[unit];
930 		while (1) {
931 			c = regs->du_sra << 8;
932 			if ((c & 0x0100) == 0)
933 				break;
934 			c |= regs->du_rba;
935 			if (sc->incnt == SERIBUF_SIZE)
936 				++sc->ovfl;
937 			else {
938 				*sc->wptr++ = c;
939 				if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
940 					sc->wptr = sc->inbuf;
941 				++sc->incnt;
942 				if (sc->incnt > SERIBUF_SIZE - 16)
943 					regs->du_btrst = 1;
944 			}
945 			if (c & 0x1000)
946 				regs->du_cra = 0x40;
947 		}
948 	}
949 	if (istat & 0x20) {		/* channel B receive interrupt */
950 		sc = mfcscd.cd_devs[unit + 1];
951 		while (1) {
952 			c = regs->du_srb << 8;
953 			if ((c & 0x0100) == 0)
954 				break;
955 			c |= regs->du_rbb;
956 			if (sc->incnt == SERIBUF_SIZE)
957 				++sc->ovfl;
958 			else {
959 				*sc->wptr++ = c;
960 				if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
961 					sc->wptr = sc->inbuf;
962 				++sc->incnt;
963 				if (sc->incnt > SERIBUF_SIZE - 16)
964 					regs->du_btrst = 2;
965 			}
966 			if (c & 0x1000)
967 				regs->du_crb = 0x40;
968 		}
969 	}
970 	if (istat & 0x01) {		/* channel A transmit interrupt */
971 		tp = mfcs_tty[unit];
972 		sc = mfcscd.cd_devs[unit];
973 		if (sc->ptr == sc->end) {
974 			tp->t_state &= ~(TS_BUSY | TS_FLUSH);
975 			scc->imask &= ~0x01;
976 			regs->du_imr = scc->imask;
977 			add_sicallback (tp->t_line ?
978 			    linesw[tp->t_line].l_start : mfcsstart,
979 			    tp, NULL);
980 
981 		}
982 		else
983 			regs->du_tba = *sc->ptr++;
984 	}
985 	if (istat & 0x10) {		/* channel B transmit interrupt */
986 		tp = mfcs_tty[unit + 1];
987 		sc = mfcscd.cd_devs[unit + 1];
988 		if (sc->ptr == sc->end) {
989 			tp->t_state &= ~(TS_BUSY | TS_FLUSH);
990 			scc->imask &= ~0x10;
991 			regs->du_imr = scc->imask;
992 			add_sicallback (tp->t_line ?
993 			    linesw[tp->t_line].l_start : mfcsstart,
994 			    tp, NULL);
995 		}
996 		else
997 			regs->du_tbb = *sc->ptr++;
998 	}
999 	if (istat & 0x80) {		/* input port change interrupt */
1000 		c = regs->du_ipcr;
1001 		printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c);
1002 	}
1003 	return(1);
1004 }
1005 
1006 int
1007 mfcsxintr(unit)
1008 	int unit;
1009 {
1010 	int s1, s2, ovfl;
1011 	struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1012 	struct tty *tp = mfcs_tty[unit];
1013 
1014 	/*
1015 	 * Make sure we're not interrupted by another
1016 	 * vbl, but allow level6 ints
1017 	 */
1018 	s1 = spltty();
1019 
1020 	/*
1021 	 * pass along any acumulated information
1022 	 * while input is not blocked
1023 	 */
1024 	while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) {
1025 		/*
1026 		 * no collision with ser_fastint()
1027 		 */
1028 		mfcseint(unit, *sc->rptr++);
1029 
1030 		ovfl = 0;
1031 		/* lock against mfcs_fastint() */
1032 		s2 = splser();
1033 		--sc->incnt;
1034 		if (sc->rptr == sc->inbuf + SERIBUF_SIZE)
1035 			sc->rptr = sc->inbuf;
1036 		if (sc->ovfl != 0) {
1037 			ovfl = sc->ovfl;
1038 			sc->ovfl = 0;
1039 		}
1040 		splx(s2);
1041 		if (ovfl != 0)
1042 			log(LOG_WARNING, "%s: %d buffer overflow!\n",
1043 			    sc->sc_dev.dv_xname, ovfl);
1044 	}
1045 	if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) {
1046 		sc->sc_regs->du_btst = 1 << unit;	/* XXXX */
1047 	}
1048 	splx(s1);
1049 }
1050 
1051 int
1052 mfcseint(unit, stat)
1053 	int unit, stat;
1054 {
1055 	struct tty *tp;
1056 	u_char ch;
1057 	int c;
1058 
1059 	tp = mfcs_tty[unit];
1060 	ch = stat & 0xff;
1061 	c = ch;
1062 
1063 	if ((tp->t_state & TS_ISOPEN) == 0) {
1064 #ifdef KGDB
1065 		/* we don't care about parity errors */
1066 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
1067 			kgdb_connect(0);	/* trap into kgdb */
1068 #endif
1069 		return;
1070 	}
1071 
1072 	/*
1073 	 * Check for break and (if enabled) parity error.
1074 	 */
1075 	if (stat & 0xc000)
1076 		c |= TTY_FE;
1077 	else if (stat & 0x2000)
1078 			c |= TTY_PE;
1079 
1080 	if (stat & 0x1000)
1081 		log(LOG_WARNING, "%s: fifo overflow\n",
1082 		    ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname);
1083 
1084 	(*linesw[tp->t_line].l_rint)(c, tp);
1085 }
1086 
1087 /*
1088  * This interrupt is periodically invoked in the vertical blank
1089  * interrupt.  It's used to keep track of the modem control lines
1090  * and (new with the fast_int code) to move accumulated data
1091  * up into the tty layer.
1092  */
1093 void
1094 mfcsmint(unit)
1095 	int unit;
1096 {
1097 	struct tty *tp;
1098 	struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1099 	u_char stat, last, istat;
1100 
1101 	tp = mfcs_tty[unit];
1102 	if (!tp)
1103 		return;
1104 
1105 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
1106 		sc->rptr = sc->wptr = sc->inbuf;
1107 		sc->incnt = 0;
1108 		return;
1109 	}
1110 	/*
1111 	 * empty buffer
1112 	 */
1113 	mfcsxintr(unit);
1114 
1115 	stat = ~sc->sc_regs->du_ip;
1116 	last = sc->sc_mfc->last_ip;
1117 	sc->sc_mfc->last_ip = stat;
1118 
1119 	/*
1120 	 * check whether any interesting signal changed state
1121 	 */
1122 	istat = stat ^ last;
1123 
1124 	if ((istat & (0x10 << (unit & 1))) && 		/* CD changed */
1125 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
1126 		if (stat & (0x10 << (unit & 1)))
1127 			(*linesw[tp->t_line].l_modem)(tp, 1);
1128 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
1129 			sc->sc_regs->du_btrst = 0x0a << (unit & 1);
1130 		}
1131 	}
1132 }
1133