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