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