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