xref: /csrg-svn/sys/pmax/dev/scc.c (revision 63207)
156817Sralph /*-
2*63207Sbostic  * Copyright (c) 1992, 1993
3*63207Sbostic  *	The Regents of the University of California.  All rights reserved.
456817Sralph  *
556817Sralph  * This code is derived from software contributed to Berkeley by
656817Sralph  * Ralph Campbell and Rick Macklem.
756817Sralph  *
856817Sralph  * %sccs.include.redist.c%
956817Sralph  *
10*63207Sbostic  *	@(#)scc.c	8.1 (Berkeley) 06/10/93
1156817Sralph  */
1256817Sralph 
1356817Sralph /*
1456817Sralph  * Mach Operating System
1556817Sralph  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
1656817Sralph  * All Rights Reserved.
1756817Sralph  *
1856817Sralph  * Permission to use, copy, modify and distribute this software and its
1956817Sralph  * documentation is hereby granted, provided that both the copyright
2056817Sralph  * notice and this permission notice appear in all copies of the
2156817Sralph  * software, derivative works or modified versions, and any portions
2256817Sralph  * thereof, and that both notices appear in supporting documentation.
2356817Sralph  *
2456817Sralph  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
2556817Sralph  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
2656817Sralph  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
2756817Sralph  *
2856817Sralph  * Carnegie Mellon requests users of this software to return to
2956817Sralph  *
3056817Sralph  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
3156817Sralph  *  School of Computer Science
3256817Sralph  *  Carnegie Mellon University
3356817Sralph  *  Pittsburgh PA 15213-3890
3456817Sralph  *
3556817Sralph  * any improvements or extensions that they make and grant Carnegie the
3656817Sralph  * rights to redistribute these changes.
3756817Sralph  */
3856817Sralph 
3956817Sralph #include <scc.h>
4056817Sralph #if NSCC > 0
4156817Sralph /*
4256817Sralph  * Intel 82530 dual usart chip driver. Supports the serial port(s) on the
4356817Sralph  * Personal DECstation 5000/xx and DECstation 5000/1xx, plus the keyboard
4456817Sralph  * and mouse on the 5000/1xx. (Don't ask me where the A channel signals
4556817Sralph  * are on the 5000/xx.)
4656817Sralph  *
4756817Sralph  * See: Intel MicroCommunications Handbook, Section 2, pg. 155-173, 1992.
4856817Sralph  */
4956817Sralph #include <sys/param.h>
5056817Sralph #include <sys/systm.h>
5156817Sralph #include <sys/ioctl.h>
5256817Sralph #include <sys/tty.h>
5356817Sralph #include <sys/proc.h>
5456817Sralph #include <sys/map.h>
5556817Sralph #include <sys/buf.h>
5656817Sralph #include <sys/conf.h>
5756817Sralph #include <sys/file.h>
5856817Sralph #include <sys/uio.h>
5956817Sralph #include <sys/kernel.h>
6056817Sralph #include <sys/syslog.h>
6156817Sralph 
6256817Sralph #include <machine/pmioctl.h>
6356817Sralph 
6456817Sralph #include <pmax/dev/device.h>
6556817Sralph #include <pmax/dev/pdma.h>
6656817Sralph #include <pmax/dev/sccreg.h>
6756817Sralph #include <pmax/dev/fbreg.h>
6856817Sralph 
6956817Sralph #include <pmax/pmax/cons.h>
7056817Sralph #include <pmax/pmax/pmaxtype.h>
7156817Sralph 
7256817Sralph extern int pmax_boardtype;
7356817Sralph extern struct consdev cn_tab;
7456817Sralph extern void ttrstrt	__P((void *));
7556817Sralph extern void KBDReset	__P((dev_t, void (*)()));
7656817Sralph extern void MouseInit	__P((dev_t, void (*)(), int (*)()));
7756817Sralph 
7856817Sralph /*
7956817Sralph  * Driver information for auto-configuration stuff.
8056817Sralph  */
8156817Sralph int	sccprobe(), sccopen(), sccparam(), sccGetc();
8256817Sralph void	sccintr(), sccstart(), sccPutc();
8356817Sralph struct	driver sccdriver = {
8456817Sralph 	"scc", sccprobe, 0, 0, sccintr,
8556817Sralph };
8656817Sralph 
8756817Sralph #define	NSCCLINE 	(NSCC*2)
8856817Sralph #define	SCCUNIT(dev)	(minor(dev) >> 1)
8956817Sralph #define	SCCLINE(dev)	(minor(dev) & 0x1)
9056817Sralph 
9156817Sralph struct	tty scc_tty[NSCCLINE];
9256817Sralph void	(*sccDivertXInput)();	/* X windows keyboard input routine */
9356817Sralph void	(*sccMouseEvent)();	/* X windows mouse motion event routine */
9456817Sralph void	(*sccMouseButtons)();	/* X windows mouse buttons event routine */
9556817Sralph #ifdef DEBUG
9656817Sralph int	debugChar;
9756817Sralph #endif
9856817Sralph static void scc_modem_intr(), sccreset();
9956817Sralph 
10056817Sralph struct scc_softc {
10156817Sralph 	struct pdma scc_pdma[2];
10256817Sralph 	struct {
10356817Sralph 		u_char	wr1;
10456817Sralph 		u_char	wr3;
10556817Sralph 		u_char	wr4;
10656817Sralph 		u_char	wr5;
10756817Sralph 		u_char	wr14;
10856817Sralph 	} scc_wreg[2];
10956817Sralph 	int	scc_softCAR;
11056817Sralph } scc_softc[NSCC];
11156817Sralph 
11256817Sralph struct speedtab sccspeedtab[] = {
11356817Sralph 	0,	0,
11456817Sralph 	50,	4606,
11556817Sralph 	75,	3070,
11656817Sralph 	110,	2093,
11756817Sralph 	134,	1711,
11856817Sralph 	150,	1534,
11956817Sralph 	300,	766,
12056817Sralph 	600,	382,
12156817Sralph 	1200,	190,
12256817Sralph 	1800,	126,
12356817Sralph 	2400,	94,
12456817Sralph 	4800,	46,
12556817Sralph 	9600,	22,
12656817Sralph 	19200,	10,
12756817Sralph 	38400,	4,
12856817Sralph 	-1,	-1
12956817Sralph };
13056817Sralph 
13156817Sralph #ifndef	PORTSELECTOR
13256817Sralph #define	ISPEED	TTYDEF_SPEED
13356817Sralph #define	LFLAG	TTYDEF_LFLAG
13456817Sralph #else
13556817Sralph #define	ISPEED	B4800
13656817Sralph #define	LFLAG	(TTYDEF_LFLAG & ~ECHO)
13756817Sralph #endif
13856817Sralph 
13956817Sralph /*
14056817Sralph  * Test to see if device is present.
14156817Sralph  * Return true if found and initialized ok.
14256817Sralph  */
14356817Sralph sccprobe(cp)
14456817Sralph 	register struct pmax_ctlr *cp;
14556817Sralph {
14656817Sralph 	register struct scc_softc *sc;
14756817Sralph 	register struct pdma *pdp;
14856817Sralph 	register struct tty *tp;
14956817Sralph 	register int cntr;
15056817Sralph 	struct tty ctty;
15156817Sralph 	struct termios cterm;
15256817Sralph 	int s;
15356817Sralph 
15456817Sralph 	if (cp->pmax_unit >= NSCC)
15556817Sralph 		return (0);
15656817Sralph 	if (badaddr(cp->pmax_addr, 2))
15756817Sralph 		return (0);
15856817Sralph 
15957234Sralph 	/*
16057234Sralph 	 * For a remote console, wait a while for previous output to
16157234Sralph 	 * complete.
16257234Sralph 	 */
16357234Sralph 	if (major(cn_tab.cn_dev) == SCCDEV && cn_tab.cn_screen == 0 &&
16457234Sralph 		SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit)
16557234Sralph 		DELAY(10000);
16657234Sralph 
16756817Sralph 	sc = &scc_softc[cp->pmax_unit];
16856817Sralph 	pdp = &sc->scc_pdma[0];
16956817Sralph 
17056817Sralph 	/* init pseudo DMA structures */
17156817Sralph 	tp = &scc_tty[cp->pmax_unit * 2];
17256817Sralph 	for (cntr = 0; cntr < 2; cntr++) {
17356817Sralph 		pdp->p_addr = (void *)cp->pmax_addr;
17456817Sralph 		pdp->p_arg = (int)tp;
17556817Sralph 		pdp->p_fcn = (void (*)())0;
17656817Sralph 		tp->t_addr = (caddr_t)pdp;
17756817Sralph 		tp->t_dev = (dev_t)((cp->pmax_unit << 1) | cntr);
17856817Sralph 		pdp++, tp++;
17956817Sralph 	}
18056817Sralph 	sc->scc_softCAR = cp->pmax_flags | 0x2;
18156817Sralph 
18256817Sralph 	/* reset chip */
18356817Sralph 	sccreset(sc);
18456817Sralph 
18556817Sralph 	/*
18656817Sralph 	 * Special handling for consoles.
18756817Sralph 	 */
18856817Sralph 	if (cn_tab.cn_screen) {
18956817Sralph 		if (cn_tab.cn_kbdgetc == sccGetc) {
19058793Sralph 			if (cp->pmax_unit == 1) {
19156817Sralph 				s = spltty();
19256817Sralph 				ctty.t_dev = makedev(SCCDEV, SCCKBD_PORT);
19356817Sralph 				cterm.c_cflag = CS8;
19456817Sralph 				cterm.c_ospeed = cterm.c_ispeed = 4800;
19556817Sralph 				(void) sccparam(&ctty, &cterm);
19658793Sralph 				DELAY(10000);
19758793Sralph #ifdef notyet
19858793Sralph 				/*
19958793Sralph 				 * For some reason doing this hangs the 3min
20058793Sralph 				 * during booting. Fortunately the keyboard
20158793Sralph 				 * works ok without it.
20258793Sralph 				 */
20356817Sralph 				KBDReset(ctty.t_dev, sccPutc);
20458793Sralph #endif
20558793Sralph 				DELAY(10000);
20656817Sralph 				splx(s);
20758793Sralph 			} else if (cp->pmax_unit == 0) {
20856817Sralph 				s = spltty();
20956817Sralph 				ctty.t_dev = makedev(SCCDEV, SCCMOUSE_PORT);
21056817Sralph 				cterm.c_cflag = CS8 | PARENB | PARODD;
21156817Sralph 				cterm.c_ospeed = cterm.c_ispeed = 4800;
21256817Sralph 				(void) sccparam(&ctty, &cterm);
21358793Sralph 				DELAY(10000);
21456817Sralph 				MouseInit(ctty.t_dev, sccPutc, sccGetc);
21558793Sralph 				DELAY(10000);
21656817Sralph 				splx(s);
21756817Sralph 			}
21856817Sralph 		}
21956817Sralph 	} else if (SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit) {
22056817Sralph 		s = spltty();
22156817Sralph 		ctty.t_dev = cn_tab.cn_dev;
22256817Sralph 		cterm.c_cflag = CS8;
22356817Sralph 		cterm.c_ospeed = cterm.c_ispeed = 9600;
22456817Sralph 		(void) sccparam(&ctty, &cterm);
22557234Sralph 		DELAY(1000);
22656817Sralph 		cn_tab.cn_disabled = 0;
22756817Sralph 		splx(s);
22856817Sralph 	}
22957234Sralph 	printf("scc%d at nexus0 csr 0x%x priority %d\n",
23057234Sralph 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
23156817Sralph 	return (1);
23256817Sralph }
23356817Sralph 
23456817Sralph /*
23556817Sralph  * Reset the chip.
23656817Sralph  */
23756817Sralph static void
23856817Sralph sccreset(sc)
23956817Sralph 	register struct scc_softc *sc;
24056817Sralph {
24156817Sralph 	register scc_regmap_t *regs;
24256817Sralph 	register u_char val;
24356817Sralph 
24456817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
24556817Sralph 	/*
24656817Sralph 	 * Chip once-only initialization
24756817Sralph 	 *
24856817Sralph 	 * NOTE: The wiring we assume is the one on the 3min:
24956817Sralph 	 *
25056817Sralph 	 *	out	A-TxD	-->	TxD	keybd or mouse
25156817Sralph 	 *	in	A-RxD	-->	RxD	keybd or mouse
25256817Sralph 	 *	out	A-DTR~	-->	DTR	comm
25356817Sralph 	 *	out	A-RTS~	-->	RTS	comm
25456817Sralph 	 *	in	A-CTS~	-->	SI	comm
25556817Sralph 	 *	in	A-DCD~	-->	RI	comm
25656817Sralph 	 *	in	A-SYNCH~-->	DSR	comm
25756817Sralph 	 *	out	B-TxD	-->	TxD	comm
25856817Sralph 	 *	in	B-RxD	-->	RxD	comm
25956817Sralph 	 *	in	B-RxC	-->	TRxCB	comm
26056817Sralph 	 *	in	B-TxC	-->	RTxCB	comm
26156817Sralph 	 *	out	B-RTS~	-->	SS	comm
26256817Sralph 	 *	in	B-CTS~	-->	CTS	comm
26356817Sralph 	 *	in	B-DCD~	-->	CD	comm
26456817Sralph 	 */
26556817Sralph 	SCC_INIT_REG(regs, SCC_CHANNEL_A);
26656817Sralph 	SCC_INIT_REG(regs, SCC_CHANNEL_B);
26756817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET);
26856817Sralph 	DELAY(50000);	/*enough ? */
26956817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, 0);
27056817Sralph 
27156817Sralph 	/* program the interrupt vector */
27256817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0);
27356817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0);
27456817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS);
27556817Sralph 
27656817Sralph 	/* timing base defaults */
27756817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16;
27856817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16;
27956817Sralph 
28056817Sralph 	/* enable DTR, RTS and SS */
28156817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS;
28256817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR;
28356817Sralph 
28456817Sralph 	/* baud rates */
28556817Sralph 	val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC;
28656817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr14 = val;
28756817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr14 = val;
28856817Sralph 
28956817Sralph 	/* interrupt conditions */
29056817Sralph 	val =	SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE |
29157234Sralph 		SCC_WR1_EXT_IE;
29256817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr1 = val;
29356817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr1 = val;
29456817Sralph }
29556817Sralph 
29656817Sralph sccopen(dev, flag, mode, p)
29756817Sralph 	dev_t dev;
29856817Sralph 	int flag, mode;
29956817Sralph 	struct proc *p;
30056817Sralph {
30156817Sralph 	register struct scc_softc *sc;
30256817Sralph 	register struct tty *tp;
30356817Sralph 	register int unit, line;
30456817Sralph 	int s, error = 0;
30556817Sralph 
30656817Sralph 	unit = SCCUNIT(dev);
30756817Sralph 	if (unit >= NSCC)
30856817Sralph 		return (ENXIO);
30956817Sralph 	line = SCCLINE(dev);
31056817Sralph 	sc = &scc_softc[unit];
31156817Sralph 	if (sc->scc_pdma[line].p_addr == (void *)0)
31256817Sralph 		return (ENXIO);
31356817Sralph 	tp = &scc_tty[minor(dev)];
31456817Sralph 	tp->t_addr = (caddr_t)&sc->scc_pdma[line];
31556817Sralph 	tp->t_oproc = sccstart;
31656817Sralph 	tp->t_param = sccparam;
31756817Sralph 	tp->t_dev = dev;
31856817Sralph 	if ((tp->t_state & TS_ISOPEN) == 0) {
31956817Sralph 		tp->t_state |= TS_WOPEN;
32056817Sralph 		ttychars(tp);
32156817Sralph #ifndef PORTSELECTOR
32256817Sralph 		if (tp->t_ispeed == 0) {
32356817Sralph #endif
32456817Sralph 			tp->t_iflag = TTYDEF_IFLAG;
32556817Sralph 			tp->t_oflag = TTYDEF_OFLAG;
32656817Sralph 			tp->t_cflag = TTYDEF_CFLAG;
32756817Sralph 			tp->t_lflag = LFLAG;
32856817Sralph 			tp->t_ispeed = tp->t_ospeed = ISPEED;
32956817Sralph #ifdef PORTSELECTOR
33056817Sralph 			tp->t_cflag |= HUPCL;
33156817Sralph #else
33256817Sralph 		}
33356817Sralph #endif
33456817Sralph 		(void) sccparam(tp, &tp->t_termios);
33556817Sralph 		ttsetwater(tp);
33656817Sralph 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
33756817Sralph 		return (EBUSY);
33856817Sralph 	(void) sccmctl(dev, DML_DTR, DMSET);
33956817Sralph 	s = spltty();
34056817Sralph 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
34156817Sralph 	       !(tp->t_state & TS_CARR_ON)) {
34256817Sralph 		tp->t_state |= TS_WOPEN;
34356817Sralph 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
34456817Sralph 		    ttopen, 0))
34556817Sralph 			break;
34656817Sralph 	}
34756817Sralph 	splx(s);
34856817Sralph 	if (error)
34956817Sralph 		return (error);
35056817Sralph 	return ((*linesw[tp->t_line].l_open)(dev, tp));
35156817Sralph }
35256817Sralph 
35356817Sralph /*ARGSUSED*/
35456817Sralph sccclose(dev, flag, mode, p)
35556817Sralph 	dev_t dev;
35656817Sralph 	int flag, mode;
35756817Sralph 	struct proc *p;
35856817Sralph {
35956817Sralph 	register struct scc_softc *sc = &scc_softc[SCCUNIT(dev)];
36056817Sralph 	register struct tty *tp;
36156817Sralph 	register int bit, line;
36256817Sralph 
36356817Sralph 	tp = &scc_tty[minor(dev)];
36456817Sralph 	line = SCCLINE(dev);
36556817Sralph 	if (sc->scc_wreg[line].wr5 & SCC_WR5_SEND_BREAK) {
36656817Sralph 		sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
36756817Sralph 		ttyoutput(0, tp);
36856817Sralph 	}
36956817Sralph 	(*linesw[tp->t_line].l_close)(tp, flag);
37056817Sralph 	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
37156817Sralph 	    !(tp->t_state & TS_ISOPEN))
37256817Sralph 		(void) sccmctl(dev, 0, DMSET);
37356817Sralph 	return (ttyclose(tp));
37456817Sralph }
37556817Sralph 
37656817Sralph sccread(dev, uio, flag)
37756817Sralph 	dev_t dev;
37856817Sralph 	struct uio *uio;
37956817Sralph {
38056817Sralph 	register struct tty *tp;
38156817Sralph 
38256817Sralph 	tp = &scc_tty[minor(dev)];
38356817Sralph 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
38456817Sralph }
38556817Sralph 
38656817Sralph sccwrite(dev, uio, flag)
38756817Sralph 	dev_t dev;
38856817Sralph 	struct uio *uio;
38956817Sralph {
39056817Sralph 	register struct tty *tp;
39156817Sralph 
39256817Sralph 	tp = &scc_tty[minor(dev)];
39356817Sralph 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
39456817Sralph }
39556817Sralph 
39656817Sralph /*ARGSUSED*/
39756817Sralph sccioctl(dev, cmd, data, flag, p)
39856817Sralph 	dev_t dev;
39956817Sralph 	int cmd;
40056817Sralph 	caddr_t data;
40156817Sralph 	int flag;
40256817Sralph 	struct proc *p;
40356817Sralph {
40456817Sralph 	register struct scc_softc *sc;
40556817Sralph 	register struct tty *tp;
40656817Sralph 	int error, line;
40756817Sralph 
40856817Sralph 	tp = &scc_tty[minor(dev)];
40956817Sralph 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
41056817Sralph 	if (error >= 0)
41156817Sralph 		return (error);
41256817Sralph 	error = ttioctl(tp, cmd, data, flag);
41356817Sralph 	if (error >= 0)
41456817Sralph 		return (error);
41556817Sralph 
41656817Sralph 	line = SCCLINE(dev);
41756817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
41856817Sralph 	switch (cmd) {
41956817Sralph 
42056817Sralph 	case TIOCSBRK:
42156817Sralph 		sc->scc_wreg[line].wr5 |= SCC_WR5_SEND_BREAK;
42256817Sralph 		ttyoutput(0, tp);
42356817Sralph 		break;
42456817Sralph 
42556817Sralph 	case TIOCCBRK:
42656817Sralph 		sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
42756817Sralph 		ttyoutput(0, tp);
42856817Sralph 		break;
42956817Sralph 
43056817Sralph 	case TIOCSDTR:
43156817Sralph 		(void) sccmctl(dev, DML_DTR|DML_RTS, DMBIS);
43256817Sralph 		break;
43356817Sralph 
43456817Sralph 	case TIOCCDTR:
43556817Sralph 		(void) sccmctl(dev, DML_DTR|DML_RTS, DMBIC);
43656817Sralph 		break;
43756817Sralph 
43856817Sralph 	case TIOCMSET:
43956817Sralph 		(void) sccmctl(dev, *(int *)data, DMSET);
44056817Sralph 		break;
44156817Sralph 
44256817Sralph 	case TIOCMBIS:
44356817Sralph 		(void) sccmctl(dev, *(int *)data, DMBIS);
44456817Sralph 		break;
44556817Sralph 
44656817Sralph 	case TIOCMBIC:
44756817Sralph 		(void) sccmctl(dev, *(int *)data, DMBIC);
44856817Sralph 		break;
44956817Sralph 
45056817Sralph 	case TIOCMGET:
45156817Sralph 		*(int *)data = sccmctl(dev, 0, DMGET);
45256817Sralph 		break;
45356817Sralph 
45456817Sralph 	default:
45556817Sralph 		return (ENOTTY);
45656817Sralph 	}
45756817Sralph 	return (0);
45856817Sralph }
45956817Sralph 
46056817Sralph sccparam(tp, t)
46156817Sralph 	register struct tty *tp;
46256817Sralph 	register struct termios *t;
46356817Sralph {
46456817Sralph 	register struct scc_softc *sc;
46556817Sralph 	register scc_regmap_t *regs;
46656817Sralph 	register int line;
46756817Sralph 	register u_char value, wvalue;
46856817Sralph 	register int cflag = t->c_cflag;
46956817Sralph 	int ospeed;
47056817Sralph 
47156817Sralph         if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
47256817Sralph                 return (EINVAL);
47356817Sralph 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
47456817Sralph 	line = SCCLINE(tp->t_dev);
47556817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
47656817Sralph 	ospeed = ttspeedtab(t->c_ospeed, sccspeedtab);
47756817Sralph         if (ospeed < 0)
47856817Sralph                 return (EINVAL);
47956817Sralph         /* and copy to tty */
48056817Sralph         tp->t_ispeed = t->c_ispeed;
48156817Sralph         tp->t_ospeed = t->c_ospeed;
48256817Sralph         tp->t_cflag = cflag;
48356817Sralph 
48456817Sralph 	/*
48556817Sralph 	 * Handle console specially.
48656817Sralph 	 */
48756817Sralph 	if (cn_tab.cn_screen) {
48856817Sralph 		if (minor(tp->t_dev) == SCCKBD_PORT) {
48956817Sralph 			cflag = CS8;
49056817Sralph 			ospeed = ttspeedtab(4800, sccspeedtab);
49156817Sralph 		} else if (minor(tp->t_dev) == SCCMOUSE_PORT) {
49256817Sralph 			cflag = CS8 | PARENB | PARODD;
49356817Sralph 			ospeed = ttspeedtab(4800, sccspeedtab);
49456817Sralph 		}
49556817Sralph 	} else if (tp->t_dev == cn_tab.cn_dev) {
49656817Sralph 		cflag = CS8;
49756817Sralph 		ospeed = ttspeedtab(9600, sccspeedtab);
49856817Sralph 	}
49956817Sralph 	if (ospeed == 0) {
50056817Sralph 		(void) sccmctl(tp->t_dev, 0, DMSET);	/* hang up line */
50156817Sralph 		return (0);
50256817Sralph 	}
50356817Sralph 
50456817Sralph 	/* reset line */
50556817Sralph 	if (line == SCC_CHANNEL_A)
50656817Sralph 		value = SCC_WR9_RESET_CHA_A;
50756817Sralph 	else
50856817Sralph 		value = SCC_WR9_RESET_CHA_B;
50956817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, value);
51056817Sralph 	DELAY(25);
51156817Sralph 
51256817Sralph 	/* stop bits, normally 1 */
51356817Sralph 	value = sc->scc_wreg[line].wr4 & 0xf0;
51456817Sralph 	if (cflag & CSTOPB)
51556817Sralph 		value |= SCC_WR4_2_STOP;
51656817Sralph 	else
51756817Sralph 		value |= SCC_WR4_1_STOP;
51856817Sralph 	if ((cflag & PARODD) == 0)
51956817Sralph 		value |= SCC_WR4_EVEN_PARITY;
52056817Sralph 	if (cflag & PARENB)
52156817Sralph 		value |= SCC_WR4_PARITY_ENABLE;
52256817Sralph 
52356817Sralph 	/* set it now, remember it must be first after reset */
52456817Sralph 	sc->scc_wreg[line].wr4 = value;
52556817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR4, value);
52656817Sralph 
52756817Sralph 	/* vector again */
52856817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR2, 0xf0);
52956817Sralph 
53056817Sralph 	/* clear break, keep rts dtr */
53156817Sralph 	wvalue = sc->scc_wreg[line].wr5 & (SCC_WR5_DTR|SCC_WR5_RTS);
53256817Sralph 	switch (cflag & CSIZE) {
53356817Sralph 	case CS5:
53456817Sralph 		value = SCC_WR3_RX_5_BITS;
53556817Sralph 		wvalue |= SCC_WR5_TX_5_BITS;
53656817Sralph 		break;
53756817Sralph 	case CS6:
53856817Sralph 		value = SCC_WR3_RX_6_BITS;
53956817Sralph 		wvalue |= SCC_WR5_TX_6_BITS;
54056817Sralph 		break;
54156817Sralph 	case CS7:
54256817Sralph 		value = SCC_WR3_RX_7_BITS;
54356817Sralph 		wvalue |= SCC_WR5_TX_7_BITS;
54456817Sralph 		break;
54556817Sralph 	case CS8:
54656817Sralph 	default:
54756817Sralph 		value = SCC_WR3_RX_8_BITS;
54856817Sralph 		wvalue |= SCC_WR5_TX_8_BITS;
54956817Sralph 	};
55056817Sralph 	sc->scc_wreg[line].wr3 = value;
55156817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR3, value);
55256817Sralph 	sc->scc_wreg[line].wr5 = wvalue;
55356817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR5, wvalue);
55456817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR6, 0);
55556817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR7, 0);
55656817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, SCC_WR9_VIS);
55756817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR10, 0);
55856817Sralph 	value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR |
55956817Sralph 		SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR;
56056817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR11, value);
56156817Sralph 	SCC_SET_TIMING_BASE(regs, line, ospeed);
56256817Sralph 	value = sc->scc_wreg[line].wr14;
56356817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR14, value);
56456817Sralph 	value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE;
56556817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR15, value);
56656817Sralph 
56756817Sralph 	/* and now the enables */
56856817Sralph 	value = sc->scc_wreg[line].wr3 | SCC_WR3_RX_ENABLE;
56956817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR3, value);
57056817Sralph 	value = sc->scc_wreg[line].wr5 | SCC_WR5_TX_ENABLE;
57156817Sralph 	sc->scc_wreg[line].wr5 = value;
57256817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR5, value);
57356817Sralph 
57456817Sralph 	/* master inter enable */
57556817Sralph 	value = SCC_WR9_MASTER_IE | SCC_WR9_VIS;
57656817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, value);
57756817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1);
57856817Sralph 	MachEmptyWriteBuffer();
57956817Sralph 	return (0);
58056817Sralph }
58156817Sralph 
58256817Sralph /*
58356817Sralph  * Check for interrupts from all devices.
58456817Sralph  */
58556817Sralph void
58656817Sralph sccintr(unit)
58756817Sralph 	register int unit;
58856817Sralph {
58956817Sralph 	register scc_regmap_t *regs;
59056817Sralph 	register struct tty *tp;
59156817Sralph 	register struct pdma *dp;
59256817Sralph 	register struct scc_softc *sc;
59356817Sralph 	register int cc, chan, rr1, rr2, rr3;
59456817Sralph 	int overrun = 0;
59556817Sralph 
59656817Sralph 	sc = &scc_softc[unit];
59756817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
59856817Sralph 	unit <<= 1;
59956817Sralph 	for (;;) {
60056817Sralph 	    SCC_READ_REG(regs, SCC_CHANNEL_B, SCC_RR2, rr2);
60156817Sralph 	    rr2 = SCC_RR2_STATUS(rr2);
60256817Sralph 	    /* are we done yet ? */
60356817Sralph 	    if (rr2 == 6) {	/* strange, distinguished value */
60456817Sralph 		SCC_READ_REG(regs, SCC_CHANNEL_A, SCC_RR3, rr3);
60556817Sralph 		if (rr3 == 0)
60656817Sralph 			return;
60756817Sralph 	    }
60856817Sralph 
60956817Sralph 	    SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS);
61056817Sralph 	    if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {
61156817Sralph 		chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?
61256817Sralph 			SCC_CHANNEL_A : SCC_CHANNEL_B;
61356817Sralph 		tp = &scc_tty[unit | chan];
61456817Sralph 		dp = (struct pdma *)tp->t_addr;
61556817Sralph 		if (dp->p_mem < dp->p_end) {
61656817Sralph 			SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
61756817Sralph 			MachEmptyWriteBuffer();
61856817Sralph 		} else {
61956817Sralph 			tp->t_state &= ~TS_BUSY;
62056817Sralph 			if (tp->t_state & TS_FLUSH)
62156817Sralph 				tp->t_state &= ~TS_FLUSH;
62256817Sralph 			else {
62356817Sralph 				ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
62456817Sralph 				dp->p_end = dp->p_mem = tp->t_outq.c_cf;
62556817Sralph 			}
62656817Sralph 			if (tp->t_line)
62756817Sralph 				(*linesw[tp->t_line].l_start)(tp);
62856817Sralph 			else
62956817Sralph 				sccstart(tp);
63056817Sralph 			if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
63156817Sralph 				SCC_READ_REG(regs, chan, SCC_RR15, cc);
63256817Sralph 				cc &= ~SCC_WR15_TX_UNDERRUN_IE;
63356817Sralph 				SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
63456817Sralph 				cc = sc->scc_wreg[chan].wr1 & ~SCC_WR1_TX_IE;
63556817Sralph 				SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
63656817Sralph 				sc->scc_wreg[chan].wr1 = cc;
63756817Sralph 				MachEmptyWriteBuffer();
63856817Sralph 			}
63956817Sralph 		}
64057234Sralph 	    } else if (rr2 == SCC_RR2_A_RECV_DONE ||
64157234Sralph 		rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||
64257234Sralph 		rr2 == SCC_RR2_B_RECV_SPECIAL) {
64357234Sralph 		if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)
64457234Sralph 			chan = SCC_CHANNEL_A;
64557234Sralph 		else
64657234Sralph 			chan = SCC_CHANNEL_B;
64757234Sralph 		tp = &scc_tty[unit | chan];
64857234Sralph 		SCC_READ_DATA(regs, chan, cc);
64957234Sralph 		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
65057234Sralph 			rr2 == SCC_RR2_B_RECV_SPECIAL) {
65157234Sralph 			SCC_READ_REG(regs, chan, SCC_RR1, rr1);
65257234Sralph 			SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_ERROR);
65357234Sralph 			if ((rr1 & SCC_RR1_RX_OVERRUN) && overrun == 0) {
65457234Sralph 				log(LOG_WARNING, "scc%d,%d: silo overflow\n",
65557234Sralph 					unit >> 1, chan);
65657234Sralph 				overrun = 1;
65757234Sralph 			}
65857234Sralph 		}
65956817Sralph 
66056817Sralph 		/*
66156817Sralph 		 * Keyboard needs special treatment.
66256817Sralph 		 */
66356817Sralph 		if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
66456817Sralph #ifdef KADB
66556817Sralph 			if (cc == LK_DO) {
66656817Sralph 				spl0();
66756817Sralph 				kdbpanic();
66856817Sralph 				return;
66956817Sralph 			}
67056817Sralph #endif
67156817Sralph #ifdef DEBUG
67256817Sralph 			debugChar = cc;
67356817Sralph #endif
67456817Sralph 			if (sccDivertXInput) {
67556817Sralph 				(*sccDivertXInput)(cc);
67656817Sralph 				continue;
67756817Sralph 			}
67856817Sralph 			if ((cc = kbdMapChar(cc)) < 0)
67956817Sralph 				continue;
68056817Sralph 		/*
68156817Sralph 		 * Now for mousey
68256817Sralph 		 */
68356817Sralph 		} else if (tp == &scc_tty[SCCMOUSE_PORT] && sccMouseButtons) {
68456817Sralph 			register MouseReport *mrp;
68556817Sralph 			static MouseReport currentRep;
68656817Sralph 
68756817Sralph 			mrp = &currentRep;
68856817Sralph 			mrp->byteCount++;
68956817Sralph 			if (cc & MOUSE_START_FRAME) {
69056817Sralph 				/*
69156817Sralph 				 * The first mouse report byte (button state).
69256817Sralph 				 */
69356817Sralph 				mrp->state = cc;
69456817Sralph 				if (mrp->byteCount > 1)
69556817Sralph 					mrp->byteCount = 1;
69656817Sralph 			} else if (mrp->byteCount == 2) {
69756817Sralph 				/*
69856817Sralph 				 * The second mouse report byte (delta x).
69956817Sralph 				 */
70056817Sralph 				mrp->dx = cc;
70156817Sralph 			} else if (mrp->byteCount == 3) {
70256817Sralph 				/*
70356817Sralph 				 * The final mouse report byte (delta y).
70456817Sralph 				 */
70556817Sralph 				mrp->dy = cc;
70656817Sralph 				mrp->byteCount = 0;
70756817Sralph 				if (mrp->dx != 0 || mrp->dy != 0) {
70856817Sralph 					/*
70956817Sralph 					 * If the mouse moved,
71056817Sralph 					 * post a motion event.
71156817Sralph 					 */
71256817Sralph 					(*sccMouseEvent)(mrp);
71356817Sralph 				}
71456817Sralph 				(*sccMouseButtons)(mrp);
71556817Sralph 			}
71656817Sralph 			continue;
71756817Sralph 		}
71856817Sralph 		if (!(tp->t_state & TS_ISOPEN)) {
71956817Sralph 			wakeup((caddr_t)&tp->t_rawq);
72056817Sralph #ifdef PORTSELECTOR
72156817Sralph 			if (!(tp->t_state & TS_WOPEN))
72256817Sralph #endif
72356817Sralph 				continue;
72456817Sralph 		}
72557234Sralph 		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
72657234Sralph 			rr2 == SCC_RR2_B_RECV_SPECIAL) {
72757234Sralph 			if (rr1 & SCC_RR1_PARITY_ERR)
72857234Sralph 				cc |= TTY_PE;
72957234Sralph 			if (rr1 & SCC_RR1_FRAME_ERR)
73057234Sralph 				cc |= TTY_FE;
73156817Sralph 		}
73256817Sralph 		(*linesw[tp->t_line].l_rint)(cc, tp);
73356817Sralph 	    } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {
73456817Sralph 		chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?
73556817Sralph 			SCC_CHANNEL_A : SCC_CHANNEL_B;
73656817Sralph 		SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_EXT_IP);
73756817Sralph 		scc_modem_intr(unit | chan);
73856817Sralph 	    }
73956817Sralph 	}
74056817Sralph }
74156817Sralph 
74256817Sralph void
74356817Sralph sccstart(tp)
74456817Sralph 	register struct tty *tp;
74556817Sralph {
74656817Sralph 	register struct pdma *dp;
74756817Sralph 	register scc_regmap_t *regs;
74856817Sralph 	register struct scc_softc *sc;
74956817Sralph 	register int cc, chan;
75056817Sralph 	u_char temp;
75157234Sralph 	int s, sendone;
75256817Sralph 
75356817Sralph 	dp = (struct pdma *)tp->t_addr;
75456817Sralph 	regs = (scc_regmap_t *)dp->p_addr;
75556817Sralph 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
75656817Sralph 	s = spltty();
75756817Sralph 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
75856817Sralph 		goto out;
75956817Sralph 	if (tp->t_outq.c_cc <= tp->t_lowat) {
76056817Sralph 		if (tp->t_state & TS_ASLEEP) {
76156817Sralph 			tp->t_state &= ~TS_ASLEEP;
76256817Sralph 			wakeup((caddr_t)&tp->t_outq);
76356817Sralph 		}
76456817Sralph 		selwakeup(&tp->t_wsel);
76556817Sralph 	}
76656817Sralph 	if (tp->t_outq.c_cc == 0)
76756817Sralph 		goto out;
76856817Sralph 	/* handle console specially */
76956817Sralph 	if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
77056817Sralph 		while (tp->t_outq.c_cc > 0) {
77156817Sralph 			cc = getc(&tp->t_outq) & 0x7f;
77256817Sralph 			cnputc(cc);
77356817Sralph 		}
77456817Sralph 		/*
77556817Sralph 		 * After we flush the output queue we may need to wake
77656817Sralph 		 * up the process that made the output.
77756817Sralph 		 */
77856817Sralph 		if (tp->t_outq.c_cc <= tp->t_lowat) {
77956817Sralph 			if (tp->t_state & TS_ASLEEP) {
78056817Sralph 				tp->t_state &= ~TS_ASLEEP;
78156817Sralph 				wakeup((caddr_t)&tp->t_outq);
78256817Sralph 			}
78356817Sralph 			selwakeup(&tp->t_wsel);
78456817Sralph 		}
78556817Sralph 		goto out;
78656817Sralph 	}
78756817Sralph 	if (tp->t_flags & (RAW|LITOUT))
78856817Sralph 		cc = ndqb(&tp->t_outq, 0);
78956817Sralph 	else {
79056817Sralph 		cc = ndqb(&tp->t_outq, 0200);
79156817Sralph 		if (cc == 0) {
79256817Sralph 			cc = getc(&tp->t_outq);
79356817Sralph 			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
79456817Sralph 			tp->t_state |= TS_TIMEOUT;
79556817Sralph 			goto out;
79656817Sralph 		}
79756817Sralph 	}
79856817Sralph 	tp->t_state |= TS_BUSY;
79956817Sralph 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
80056817Sralph 	dp->p_end += cc;
80156817Sralph 
80256817Sralph 	/*
80356817Sralph 	 * Enable transmission and send the first char, as required.
80456817Sralph 	 */
80556817Sralph 	chan = SCCLINE(tp->t_dev);
80657234Sralph 	SCC_READ_REG(regs, chan, SCC_RR0, temp);
80757234Sralph 	sendone = (temp & SCC_RR0_TX_EMPTY);
80856817Sralph 	SCC_READ_REG(regs, chan, SCC_RR15, temp);
80956817Sralph 	temp |= SCC_WR15_TX_UNDERRUN_IE;
81056817Sralph 	SCC_WRITE_REG(regs, chan, SCC_WR15, temp);
81156817Sralph 	temp = sc->scc_wreg[chan].wr1 | SCC_WR1_TX_IE;
81256817Sralph 	SCC_WRITE_REG(regs, chan, SCC_WR1, temp);
81356817Sralph 	sc->scc_wreg[chan].wr1 = temp;
81457234Sralph 	if (sendone) {
81556817Sralph #ifdef DIAGNOSTIC
81656817Sralph 		if (cc == 0)
81756817Sralph 			panic("sccstart: No chars");
81856817Sralph #endif
81956817Sralph 		SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
82056817Sralph 	}
82156817Sralph 	MachEmptyWriteBuffer();
82256817Sralph out:
82356817Sralph 	splx(s);
82456817Sralph }
82556817Sralph 
82656817Sralph /*
82756817Sralph  * Stop output on a line.
82856817Sralph  */
82956817Sralph /*ARGSUSED*/
83056817Sralph sccstop(tp, flag)
83156817Sralph 	register struct tty *tp;
83256817Sralph {
83356817Sralph 	register struct pdma *dp;
83456817Sralph 	register int s;
83556817Sralph 
83656817Sralph 	dp = (struct pdma *)tp->t_addr;
83756817Sralph 	s = spltty();
83856817Sralph 	if (tp->t_state & TS_BUSY) {
83956817Sralph 		dp->p_end = dp->p_mem;
84056817Sralph 		if (!(tp->t_state & TS_TTSTOP))
84156817Sralph 			tp->t_state |= TS_FLUSH;
84256817Sralph 	}
84356817Sralph 	splx(s);
84456817Sralph }
84556817Sralph 
84656817Sralph sccmctl(dev, bits, how)
84756817Sralph 	dev_t dev;
84856817Sralph 	int bits, how;
84956817Sralph {
85056817Sralph 	register struct scc_softc *sc;
85156817Sralph 	register scc_regmap_t *regs;
85256817Sralph 	register int line, mbits;
85356817Sralph 	register u_char value;
85456817Sralph 	int s;
85556817Sralph 
85656817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
85756817Sralph 	line = SCCLINE(dev);
85856817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
85956817Sralph 	s = spltty();
86056817Sralph 	/*
86156817Sralph 	 * only channel B has modem control, however the DTR and RTS
86256817Sralph 	 * pins on the comm port are wired to the DTR and RTS A channel
86356817Sralph 	 * signals.
86456817Sralph 	 */
86556817Sralph 	mbits = DML_DTR | DML_DSR | DML_CAR;
86656817Sralph 	if (line == SCC_CHANNEL_B) {
86756817Sralph 		if (sc->scc_wreg[SCC_CHANNEL_A].wr5 & SCC_WR5_DTR)
86856817Sralph 			mbits = DML_DTR | DML_DSR;
86956817Sralph 		else
87056817Sralph 			mbits = 0;
87156817Sralph 		SCC_READ_REG_ZERO(regs, SCC_CHANNEL_B, value);
87256817Sralph 		if (value & SCC_RR0_DCD)
87356817Sralph 			mbits |= DML_CAR;
87456817Sralph 	}
87556817Sralph 	switch (how) {
87656817Sralph 	case DMSET:
87756817Sralph 		mbits = bits;
87856817Sralph 		break;
87956817Sralph 
88056817Sralph 	case DMBIS:
88156817Sralph 		mbits |= bits;
88256817Sralph 		break;
88356817Sralph 
88456817Sralph 	case DMBIC:
88556817Sralph 		mbits &= ~bits;
88656817Sralph 		break;
88756817Sralph 
88856817Sralph 	case DMGET:
88956817Sralph 		(void) splx(s);
89056817Sralph 		return (mbits);
89156817Sralph 	}
89256817Sralph 	if (line == SCC_CHANNEL_B) {
89356817Sralph 		if (mbits & DML_DTR)
89456817Sralph 			sc->scc_wreg[SCC_CHANNEL_A].wr5 |= SCC_WR5_DTR;
89556817Sralph 		else
89656817Sralph 			sc->scc_wreg[SCC_CHANNEL_A].wr5 &= ~SCC_WR5_DTR;
89756817Sralph 		SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR5,
89856817Sralph 			sc->scc_wreg[SCC_CHANNEL_A].wr5);
89956817Sralph 	}
90056817Sralph 	if ((mbits & DML_DTR) && (sc->scc_softCAR & (1 << line)))
90156817Sralph 		scc_tty[minor(dev)].t_state |= TS_CARR_ON;
90256817Sralph 	(void) splx(s);
90356817Sralph 	return (mbits);
90456817Sralph }
90556817Sralph 
90656817Sralph /*
90756817Sralph  * Check for carrier transition.
90856817Sralph  */
90956817Sralph static void
91056817Sralph scc_modem_intr(dev)
91156817Sralph 	dev_t dev;
91256817Sralph {
91356817Sralph 	register scc_regmap_t *regs;
91456817Sralph 	register struct scc_softc *sc;
91556817Sralph 	register struct tty *tp;
91656817Sralph 	register int car, chan;
91756817Sralph 	register u_char value;
91856817Sralph 	int s;
91956817Sralph 
92056817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
92156817Sralph 	tp = &scc_tty[minor(dev)];
92256817Sralph 	regs = (scc_regmap_t *)((struct pdma *)tp->t_addr)->p_addr;
92356817Sralph 	chan = SCCLINE(dev);
92456817Sralph 	if (chan == SCC_CHANNEL_A)
92556817Sralph 		return;
92656817Sralph 	s = spltty();
92756817Sralph 	if (sc->scc_softCAR & (1 << chan))
92856817Sralph 		car = 1;
92956817Sralph 	else {
93056817Sralph 		SCC_READ_REG_ZERO(regs, chan, value);
93156817Sralph 		car = value & SCC_RR0_DCD;
93256817Sralph 	}
93356817Sralph 	if (car) {
93456817Sralph 		/* carrier present */
93556817Sralph 		if (!(tp->t_state & TS_CARR_ON))
93656817Sralph 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
93756817Sralph 	} else if (tp->t_state & TS_CARR_ON)
93856817Sralph 		(void)(*linesw[tp->t_line].l_modem)(tp, 0);
93956817Sralph 	splx(s);
94056817Sralph }
94156817Sralph 
94256817Sralph /*
94356817Sralph  * Get a char off the appropriate line via. a busy wait loop.
94456817Sralph  */
94556817Sralph int
94656817Sralph sccGetc(dev)
94756817Sralph 	dev_t dev;
94856817Sralph {
94956817Sralph 	register scc_regmap_t *regs;
95056817Sralph 	register int c, line;
95156817Sralph 	register u_char value;
95256817Sralph 	int s;
95356817Sralph 
95456817Sralph 	line = SCCLINE(dev);
95556817Sralph 	regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;
95656817Sralph 	if (!regs)
95756817Sralph 		return (0);
95856817Sralph 	s = spltty();
95956817Sralph 	for (;;) {
96056817Sralph 		SCC_READ_REG(regs, line, SCC_RR0, value);
96156817Sralph 		if (value & SCC_RR0_RX_AVAIL) {
96256817Sralph 			SCC_READ_REG(regs, line, SCC_RR1, value);
96358793Sralph 			SCC_READ_DATA(regs, line, c);
96456817Sralph 			if (value & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN |
96556817Sralph 				SCC_RR1_FRAME_ERR)) {
96656817Sralph 				SCC_WRITE_REG(regs, line, SCC_WR0, SCC_RESET_ERROR);
96756817Sralph 				SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
96856817Sralph 					SCC_RESET_HIGHEST_IUS);
96956817Sralph 			} else {
97056817Sralph 				SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
97156817Sralph 					SCC_RESET_HIGHEST_IUS);
97256817Sralph 				splx(s);
97356817Sralph 				return (c & 0xff);
97456817Sralph 			}
97556817Sralph 		} else
97656817Sralph 			DELAY(10);
97756817Sralph 	}
97856817Sralph }
97956817Sralph 
98056817Sralph /*
98156817Sralph  * Send a char on a port, via a busy wait loop.
98256817Sralph  */
98356817Sralph void
98456817Sralph sccPutc(dev, c)
98556817Sralph 	dev_t dev;
98656817Sralph 	int c;
98756817Sralph {
98856817Sralph 	register scc_regmap_t *regs;
98957234Sralph 	register int line;
99056817Sralph 	register u_char value;
99156817Sralph 	int s;
99256817Sralph 
99356817Sralph 	s = spltty();
99456817Sralph 	line = SCCLINE(dev);
99556817Sralph 	regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;
99657234Sralph 
99756817Sralph 	/*
99856817Sralph 	 * Wait for transmitter to be not busy.
99956817Sralph 	 */
100056817Sralph 	do {
100156817Sralph 		SCC_READ_REG(regs, line, SCC_RR0, value);
100257234Sralph 		if (value & SCC_RR0_TX_EMPTY)
100357234Sralph 			break;
100457234Sralph 		DELAY(100);
100557234Sralph 	} while (1);
100657234Sralph 
100757234Sralph 	/*
100857234Sralph 	 * Send the char.
100957234Sralph 	 */
101057234Sralph 	SCC_WRITE_DATA(regs, line, c);
101157234Sralph 	MachEmptyWriteBuffer();
101256817Sralph 	splx(s);
101356817Sralph }
101456817Sralph #endif /* NSCC */
1015