xref: /csrg-svn/sys/pmax/dev/scc.c (revision 57234)
156817Sralph /*-
256817Sralph  * Copyright (c) 1992 The Regents of the University of California.
356817Sralph  * 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*57234Sralph  *	@(#)scc.c	7.2 (Berkeley) 12/20/92
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 
159*57234Sralph 	/*
160*57234Sralph 	 * For a remote console, wait a while for previous output to
161*57234Sralph 	 * complete.
162*57234Sralph 	 */
163*57234Sralph 	if (major(cn_tab.cn_dev) == SCCDEV && cn_tab.cn_screen == 0 &&
164*57234Sralph 		SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit)
165*57234Sralph 		DELAY(10000);
166*57234Sralph 
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) {
19056817Sralph 			if (cp->pmax_unit == 0) {
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);
196*57234Sralph 				DELAY(1000);
19756817Sralph 				KBDReset(ctty.t_dev, sccPutc);
19856817Sralph 				splx(s);
19956817Sralph 			} else if (cp->pmax_unit == 1) {
20056817Sralph 				s = spltty();
20156817Sralph 				ctty.t_dev = makedev(SCCDEV, SCCMOUSE_PORT);
20256817Sralph 				cterm.c_cflag = CS8 | PARENB | PARODD;
20356817Sralph 				cterm.c_ospeed = cterm.c_ispeed = 4800;
20456817Sralph 				(void) sccparam(&ctty, &cterm);
205*57234Sralph 				DELAY(1000);
20656817Sralph 				MouseInit(ctty.t_dev, sccPutc, sccGetc);
20756817Sralph 				splx(s);
20856817Sralph 			}
20956817Sralph 		}
21056817Sralph 	} else if (SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit) {
21156817Sralph 		s = spltty();
21256817Sralph 		ctty.t_dev = cn_tab.cn_dev;
21356817Sralph 		cterm.c_cflag = CS8;
21456817Sralph 		cterm.c_ospeed = cterm.c_ispeed = 9600;
21556817Sralph 		(void) sccparam(&ctty, &cterm);
216*57234Sralph 		DELAY(1000);
21756817Sralph 		cn_tab.cn_disabled = 0;
21856817Sralph 		splx(s);
21956817Sralph 	}
220*57234Sralph 	printf("scc%d at nexus0 csr 0x%x priority %d\n",
221*57234Sralph 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
22256817Sralph 	return (1);
22356817Sralph }
22456817Sralph 
22556817Sralph /*
22656817Sralph  * Reset the chip.
22756817Sralph  */
22856817Sralph static void
22956817Sralph sccreset(sc)
23056817Sralph 	register struct scc_softc *sc;
23156817Sralph {
23256817Sralph 	register scc_regmap_t *regs;
23356817Sralph 	register u_char val;
23456817Sralph 
23556817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
23656817Sralph 	/*
23756817Sralph 	 * Chip once-only initialization
23856817Sralph 	 *
23956817Sralph 	 * NOTE: The wiring we assume is the one on the 3min:
24056817Sralph 	 *
24156817Sralph 	 *	out	A-TxD	-->	TxD	keybd or mouse
24256817Sralph 	 *	in	A-RxD	-->	RxD	keybd or mouse
24356817Sralph 	 *	out	A-DTR~	-->	DTR	comm
24456817Sralph 	 *	out	A-RTS~	-->	RTS	comm
24556817Sralph 	 *	in	A-CTS~	-->	SI	comm
24656817Sralph 	 *	in	A-DCD~	-->	RI	comm
24756817Sralph 	 *	in	A-SYNCH~-->	DSR	comm
24856817Sralph 	 *	out	B-TxD	-->	TxD	comm
24956817Sralph 	 *	in	B-RxD	-->	RxD	comm
25056817Sralph 	 *	in	B-RxC	-->	TRxCB	comm
25156817Sralph 	 *	in	B-TxC	-->	RTxCB	comm
25256817Sralph 	 *	out	B-RTS~	-->	SS	comm
25356817Sralph 	 *	in	B-CTS~	-->	CTS	comm
25456817Sralph 	 *	in	B-DCD~	-->	CD	comm
25556817Sralph 	 */
25656817Sralph 	SCC_INIT_REG(regs, SCC_CHANNEL_A);
25756817Sralph 	SCC_INIT_REG(regs, SCC_CHANNEL_B);
25856817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET);
25956817Sralph 	DELAY(50000);	/*enough ? */
26056817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, 0);
26156817Sralph 
26256817Sralph 	/* program the interrupt vector */
26356817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0);
26456817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0);
26556817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS);
26656817Sralph 
26756817Sralph 	/* timing base defaults */
26856817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16;
26956817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16;
27056817Sralph 
27156817Sralph 	/* enable DTR, RTS and SS */
27256817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS;
27356817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR;
27456817Sralph 
27556817Sralph 	/* baud rates */
27656817Sralph 	val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC;
27756817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr14 = val;
27856817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr14 = val;
27956817Sralph 
28056817Sralph 	/* interrupt conditions */
28156817Sralph 	val =	SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE |
282*57234Sralph 		SCC_WR1_EXT_IE;
28356817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr1 = val;
28456817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr1 = val;
28556817Sralph }
28656817Sralph 
28756817Sralph sccopen(dev, flag, mode, p)
28856817Sralph 	dev_t dev;
28956817Sralph 	int flag, mode;
29056817Sralph 	struct proc *p;
29156817Sralph {
29256817Sralph 	register struct scc_softc *sc;
29356817Sralph 	register struct tty *tp;
29456817Sralph 	register int unit, line;
29556817Sralph 	int s, error = 0;
29656817Sralph 
29756817Sralph 	unit = SCCUNIT(dev);
29856817Sralph 	if (unit >= NSCC)
29956817Sralph 		return (ENXIO);
30056817Sralph 	line = SCCLINE(dev);
30156817Sralph 	sc = &scc_softc[unit];
30256817Sralph 	if (sc->scc_pdma[line].p_addr == (void *)0)
30356817Sralph 		return (ENXIO);
30456817Sralph 	tp = &scc_tty[minor(dev)];
30556817Sralph 	tp->t_addr = (caddr_t)&sc->scc_pdma[line];
30656817Sralph 	tp->t_oproc = sccstart;
30756817Sralph 	tp->t_param = sccparam;
30856817Sralph 	tp->t_dev = dev;
30956817Sralph 	if ((tp->t_state & TS_ISOPEN) == 0) {
31056817Sralph 		tp->t_state |= TS_WOPEN;
31156817Sralph 		ttychars(tp);
31256817Sralph #ifndef PORTSELECTOR
31356817Sralph 		if (tp->t_ispeed == 0) {
31456817Sralph #endif
31556817Sralph 			tp->t_iflag = TTYDEF_IFLAG;
31656817Sralph 			tp->t_oflag = TTYDEF_OFLAG;
31756817Sralph 			tp->t_cflag = TTYDEF_CFLAG;
31856817Sralph 			tp->t_lflag = LFLAG;
31956817Sralph 			tp->t_ispeed = tp->t_ospeed = ISPEED;
32056817Sralph #ifdef PORTSELECTOR
32156817Sralph 			tp->t_cflag |= HUPCL;
32256817Sralph #else
32356817Sralph 		}
32456817Sralph #endif
32556817Sralph 		(void) sccparam(tp, &tp->t_termios);
32656817Sralph 		ttsetwater(tp);
32756817Sralph 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
32856817Sralph 		return (EBUSY);
32956817Sralph 	(void) sccmctl(dev, DML_DTR, DMSET);
33056817Sralph 	s = spltty();
33156817Sralph 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
33256817Sralph 	       !(tp->t_state & TS_CARR_ON)) {
33356817Sralph 		tp->t_state |= TS_WOPEN;
33456817Sralph 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
33556817Sralph 		    ttopen, 0))
33656817Sralph 			break;
33756817Sralph 	}
33856817Sralph 	splx(s);
33956817Sralph 	if (error)
34056817Sralph 		return (error);
34156817Sralph 	return ((*linesw[tp->t_line].l_open)(dev, tp));
34256817Sralph }
34356817Sralph 
34456817Sralph /*ARGSUSED*/
34556817Sralph sccclose(dev, flag, mode, p)
34656817Sralph 	dev_t dev;
34756817Sralph 	int flag, mode;
34856817Sralph 	struct proc *p;
34956817Sralph {
35056817Sralph 	register struct scc_softc *sc = &scc_softc[SCCUNIT(dev)];
35156817Sralph 	register struct tty *tp;
35256817Sralph 	register int bit, line;
35356817Sralph 
35456817Sralph 	tp = &scc_tty[minor(dev)];
35556817Sralph 	line = SCCLINE(dev);
35656817Sralph 	if (sc->scc_wreg[line].wr5 & SCC_WR5_SEND_BREAK) {
35756817Sralph 		sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
35856817Sralph 		ttyoutput(0, tp);
35956817Sralph 	}
36056817Sralph 	(*linesw[tp->t_line].l_close)(tp, flag);
36156817Sralph 	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
36256817Sralph 	    !(tp->t_state & TS_ISOPEN))
36356817Sralph 		(void) sccmctl(dev, 0, DMSET);
36456817Sralph 	return (ttyclose(tp));
36556817Sralph }
36656817Sralph 
36756817Sralph sccread(dev, uio, flag)
36856817Sralph 	dev_t dev;
36956817Sralph 	struct uio *uio;
37056817Sralph {
37156817Sralph 	register struct tty *tp;
37256817Sralph 
37356817Sralph 	tp = &scc_tty[minor(dev)];
37456817Sralph 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
37556817Sralph }
37656817Sralph 
37756817Sralph sccwrite(dev, uio, flag)
37856817Sralph 	dev_t dev;
37956817Sralph 	struct uio *uio;
38056817Sralph {
38156817Sralph 	register struct tty *tp;
38256817Sralph 
38356817Sralph 	tp = &scc_tty[minor(dev)];
38456817Sralph 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
38556817Sralph }
38656817Sralph 
38756817Sralph /*ARGSUSED*/
38856817Sralph sccioctl(dev, cmd, data, flag, p)
38956817Sralph 	dev_t dev;
39056817Sralph 	int cmd;
39156817Sralph 	caddr_t data;
39256817Sralph 	int flag;
39356817Sralph 	struct proc *p;
39456817Sralph {
39556817Sralph 	register struct scc_softc *sc;
39656817Sralph 	register struct tty *tp;
39756817Sralph 	int error, line;
39856817Sralph 
39956817Sralph 	tp = &scc_tty[minor(dev)];
40056817Sralph 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
40156817Sralph 	if (error >= 0)
40256817Sralph 		return (error);
40356817Sralph 	error = ttioctl(tp, cmd, data, flag);
40456817Sralph 	if (error >= 0)
40556817Sralph 		return (error);
40656817Sralph 
40756817Sralph 	line = SCCLINE(dev);
40856817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
40956817Sralph 	switch (cmd) {
41056817Sralph 
41156817Sralph 	case TIOCSBRK:
41256817Sralph 		sc->scc_wreg[line].wr5 |= SCC_WR5_SEND_BREAK;
41356817Sralph 		ttyoutput(0, tp);
41456817Sralph 		break;
41556817Sralph 
41656817Sralph 	case TIOCCBRK:
41756817Sralph 		sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
41856817Sralph 		ttyoutput(0, tp);
41956817Sralph 		break;
42056817Sralph 
42156817Sralph 	case TIOCSDTR:
42256817Sralph 		(void) sccmctl(dev, DML_DTR|DML_RTS, DMBIS);
42356817Sralph 		break;
42456817Sralph 
42556817Sralph 	case TIOCCDTR:
42656817Sralph 		(void) sccmctl(dev, DML_DTR|DML_RTS, DMBIC);
42756817Sralph 		break;
42856817Sralph 
42956817Sralph 	case TIOCMSET:
43056817Sralph 		(void) sccmctl(dev, *(int *)data, DMSET);
43156817Sralph 		break;
43256817Sralph 
43356817Sralph 	case TIOCMBIS:
43456817Sralph 		(void) sccmctl(dev, *(int *)data, DMBIS);
43556817Sralph 		break;
43656817Sralph 
43756817Sralph 	case TIOCMBIC:
43856817Sralph 		(void) sccmctl(dev, *(int *)data, DMBIC);
43956817Sralph 		break;
44056817Sralph 
44156817Sralph 	case TIOCMGET:
44256817Sralph 		*(int *)data = sccmctl(dev, 0, DMGET);
44356817Sralph 		break;
44456817Sralph 
44556817Sralph 	default:
44656817Sralph 		return (ENOTTY);
44756817Sralph 	}
44856817Sralph 	return (0);
44956817Sralph }
45056817Sralph 
45156817Sralph sccparam(tp, t)
45256817Sralph 	register struct tty *tp;
45356817Sralph 	register struct termios *t;
45456817Sralph {
45556817Sralph 	register struct scc_softc *sc;
45656817Sralph 	register scc_regmap_t *regs;
45756817Sralph 	register int line;
45856817Sralph 	register u_char value, wvalue;
45956817Sralph 	register int cflag = t->c_cflag;
46056817Sralph 	int ospeed;
46156817Sralph 
46256817Sralph         if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
46356817Sralph                 return (EINVAL);
46456817Sralph 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
46556817Sralph 	line = SCCLINE(tp->t_dev);
46656817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
46756817Sralph 	ospeed = ttspeedtab(t->c_ospeed, sccspeedtab);
46856817Sralph         if (ospeed < 0)
46956817Sralph                 return (EINVAL);
47056817Sralph         /* and copy to tty */
47156817Sralph         tp->t_ispeed = t->c_ispeed;
47256817Sralph         tp->t_ospeed = t->c_ospeed;
47356817Sralph         tp->t_cflag = cflag;
47456817Sralph 
47556817Sralph 	/*
47656817Sralph 	 * Handle console specially.
47756817Sralph 	 */
47856817Sralph 	if (cn_tab.cn_screen) {
47956817Sralph 		if (minor(tp->t_dev) == SCCKBD_PORT) {
48056817Sralph 			cflag = CS8;
48156817Sralph 			ospeed = ttspeedtab(4800, sccspeedtab);
48256817Sralph 		} else if (minor(tp->t_dev) == SCCMOUSE_PORT) {
48356817Sralph 			cflag = CS8 | PARENB | PARODD;
48456817Sralph 			ospeed = ttspeedtab(4800, sccspeedtab);
48556817Sralph 		}
48656817Sralph 	} else if (tp->t_dev == cn_tab.cn_dev) {
48756817Sralph 		cflag = CS8;
48856817Sralph 		ospeed = ttspeedtab(9600, sccspeedtab);
48956817Sralph 	}
49056817Sralph 	if (ospeed == 0) {
49156817Sralph 		(void) sccmctl(tp->t_dev, 0, DMSET);	/* hang up line */
49256817Sralph 		return (0);
49356817Sralph 	}
49456817Sralph 
49556817Sralph 	/* reset line */
49656817Sralph 	if (line == SCC_CHANNEL_A)
49756817Sralph 		value = SCC_WR9_RESET_CHA_A;
49856817Sralph 	else
49956817Sralph 		value = SCC_WR9_RESET_CHA_B;
50056817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, value);
50156817Sralph 	DELAY(25);
50256817Sralph 
50356817Sralph 	/* stop bits, normally 1 */
50456817Sralph 	value = sc->scc_wreg[line].wr4 & 0xf0;
50556817Sralph 	if (cflag & CSTOPB)
50656817Sralph 		value |= SCC_WR4_2_STOP;
50756817Sralph 	else
50856817Sralph 		value |= SCC_WR4_1_STOP;
50956817Sralph 	if ((cflag & PARODD) == 0)
51056817Sralph 		value |= SCC_WR4_EVEN_PARITY;
51156817Sralph 	if (cflag & PARENB)
51256817Sralph 		value |= SCC_WR4_PARITY_ENABLE;
51356817Sralph 
51456817Sralph 	/* set it now, remember it must be first after reset */
51556817Sralph 	sc->scc_wreg[line].wr4 = value;
51656817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR4, value);
51756817Sralph 
51856817Sralph 	/* vector again */
51956817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR2, 0xf0);
52056817Sralph 
52156817Sralph 	/* clear break, keep rts dtr */
52256817Sralph 	wvalue = sc->scc_wreg[line].wr5 & (SCC_WR5_DTR|SCC_WR5_RTS);
52356817Sralph 	switch (cflag & CSIZE) {
52456817Sralph 	case CS5:
52556817Sralph 		value = SCC_WR3_RX_5_BITS;
52656817Sralph 		wvalue |= SCC_WR5_TX_5_BITS;
52756817Sralph 		break;
52856817Sralph 	case CS6:
52956817Sralph 		value = SCC_WR3_RX_6_BITS;
53056817Sralph 		wvalue |= SCC_WR5_TX_6_BITS;
53156817Sralph 		break;
53256817Sralph 	case CS7:
53356817Sralph 		value = SCC_WR3_RX_7_BITS;
53456817Sralph 		wvalue |= SCC_WR5_TX_7_BITS;
53556817Sralph 		break;
53656817Sralph 	case CS8:
53756817Sralph 	default:
53856817Sralph 		value = SCC_WR3_RX_8_BITS;
53956817Sralph 		wvalue |= SCC_WR5_TX_8_BITS;
54056817Sralph 	};
54156817Sralph 	sc->scc_wreg[line].wr3 = value;
54256817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR3, value);
54356817Sralph 	sc->scc_wreg[line].wr5 = wvalue;
54456817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR5, wvalue);
54556817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR6, 0);
54656817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR7, 0);
54756817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, SCC_WR9_VIS);
54856817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR10, 0);
54956817Sralph 	value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR |
55056817Sralph 		SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR;
55156817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR11, value);
55256817Sralph 	SCC_SET_TIMING_BASE(regs, line, ospeed);
55356817Sralph 	value = sc->scc_wreg[line].wr14;
55456817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR14, value);
55556817Sralph 	value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE;
55656817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR15, value);
55756817Sralph 
55856817Sralph 	/* and now the enables */
55956817Sralph 	value = sc->scc_wreg[line].wr3 | SCC_WR3_RX_ENABLE;
56056817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR3, value);
56156817Sralph 	value = sc->scc_wreg[line].wr5 | SCC_WR5_TX_ENABLE;
56256817Sralph 	sc->scc_wreg[line].wr5 = value;
56356817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR5, value);
56456817Sralph 
56556817Sralph 	/* master inter enable */
56656817Sralph 	value = SCC_WR9_MASTER_IE | SCC_WR9_VIS;
56756817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, value);
56856817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1);
56956817Sralph 	MachEmptyWriteBuffer();
57056817Sralph 	return (0);
57156817Sralph }
57256817Sralph 
57356817Sralph /*
57456817Sralph  * Check for interrupts from all devices.
57556817Sralph  */
57656817Sralph void
57756817Sralph sccintr(unit)
57856817Sralph 	register int unit;
57956817Sralph {
58056817Sralph 	register scc_regmap_t *regs;
58156817Sralph 	register struct tty *tp;
58256817Sralph 	register struct pdma *dp;
58356817Sralph 	register struct scc_softc *sc;
58456817Sralph 	register int cc, chan, rr1, rr2, rr3;
58556817Sralph 	int overrun = 0;
58656817Sralph 
58756817Sralph 	sc = &scc_softc[unit];
58856817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
58956817Sralph 	unit <<= 1;
59056817Sralph 	for (;;) {
59156817Sralph 	    SCC_READ_REG(regs, SCC_CHANNEL_B, SCC_RR2, rr2);
59256817Sralph 	    rr2 = SCC_RR2_STATUS(rr2);
59356817Sralph 	    /* are we done yet ? */
59456817Sralph 	    if (rr2 == 6) {	/* strange, distinguished value */
59556817Sralph 		SCC_READ_REG(regs, SCC_CHANNEL_A, SCC_RR3, rr3);
59656817Sralph 		if (rr3 == 0)
59756817Sralph 			return;
59856817Sralph 	    }
59956817Sralph 
60056817Sralph 	    SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS);
60156817Sralph 	    if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {
60256817Sralph 		chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?
60356817Sralph 			SCC_CHANNEL_A : SCC_CHANNEL_B;
60456817Sralph 		tp = &scc_tty[unit | chan];
60556817Sralph 		dp = (struct pdma *)tp->t_addr;
60656817Sralph 		if (dp->p_mem < dp->p_end) {
60756817Sralph 			SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
60856817Sralph 			MachEmptyWriteBuffer();
60956817Sralph 		} else {
61056817Sralph 			tp->t_state &= ~TS_BUSY;
61156817Sralph 			if (tp->t_state & TS_FLUSH)
61256817Sralph 				tp->t_state &= ~TS_FLUSH;
61356817Sralph 			else {
61456817Sralph 				ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
61556817Sralph 				dp->p_end = dp->p_mem = tp->t_outq.c_cf;
61656817Sralph 			}
61756817Sralph 			if (tp->t_line)
61856817Sralph 				(*linesw[tp->t_line].l_start)(tp);
61956817Sralph 			else
62056817Sralph 				sccstart(tp);
62156817Sralph 			if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
62256817Sralph 				SCC_READ_REG(regs, chan, SCC_RR15, cc);
62356817Sralph 				cc &= ~SCC_WR15_TX_UNDERRUN_IE;
62456817Sralph 				SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
62556817Sralph 				cc = sc->scc_wreg[chan].wr1 & ~SCC_WR1_TX_IE;
62656817Sralph 				SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
62756817Sralph 				sc->scc_wreg[chan].wr1 = cc;
62856817Sralph 				MachEmptyWriteBuffer();
62956817Sralph 			}
63056817Sralph 		}
631*57234Sralph 	    } else if (rr2 == SCC_RR2_A_RECV_DONE ||
632*57234Sralph 		rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||
633*57234Sralph 		rr2 == SCC_RR2_B_RECV_SPECIAL) {
634*57234Sralph 		if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)
635*57234Sralph 			chan = SCC_CHANNEL_A;
636*57234Sralph 		else
637*57234Sralph 			chan = SCC_CHANNEL_B;
638*57234Sralph 		tp = &scc_tty[unit | chan];
639*57234Sralph 		SCC_READ_DATA(regs, chan, cc);
640*57234Sralph 		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
641*57234Sralph 			rr2 == SCC_RR2_B_RECV_SPECIAL) {
642*57234Sralph 			SCC_READ_REG(regs, chan, SCC_RR1, rr1);
643*57234Sralph 			SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_ERROR);
644*57234Sralph 			if ((rr1 & SCC_RR1_RX_OVERRUN) && overrun == 0) {
645*57234Sralph 				log(LOG_WARNING, "scc%d,%d: silo overflow\n",
646*57234Sralph 					unit >> 1, chan);
647*57234Sralph 				overrun = 1;
648*57234Sralph 			}
649*57234Sralph 		}
65056817Sralph 
65156817Sralph 		/*
65256817Sralph 		 * Keyboard needs special treatment.
65356817Sralph 		 */
65456817Sralph 		if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
65556817Sralph #ifdef KADB
65656817Sralph 			if (cc == LK_DO) {
65756817Sralph 				spl0();
65856817Sralph 				kdbpanic();
65956817Sralph 				return;
66056817Sralph 			}
66156817Sralph #endif
66256817Sralph #ifdef DEBUG
66356817Sralph 			debugChar = cc;
66456817Sralph #endif
66556817Sralph 			if (sccDivertXInput) {
66656817Sralph 				(*sccDivertXInput)(cc);
66756817Sralph 				continue;
66856817Sralph 			}
66956817Sralph 			if ((cc = kbdMapChar(cc)) < 0)
67056817Sralph 				continue;
67156817Sralph 		/*
67256817Sralph 		 * Now for mousey
67356817Sralph 		 */
67456817Sralph 		} else if (tp == &scc_tty[SCCMOUSE_PORT] && sccMouseButtons) {
67556817Sralph 			register MouseReport *mrp;
67656817Sralph 			static MouseReport currentRep;
67756817Sralph 
67856817Sralph 			mrp = &currentRep;
67956817Sralph 			mrp->byteCount++;
68056817Sralph 			if (cc & MOUSE_START_FRAME) {
68156817Sralph 				/*
68256817Sralph 				 * The first mouse report byte (button state).
68356817Sralph 				 */
68456817Sralph 				mrp->state = cc;
68556817Sralph 				if (mrp->byteCount > 1)
68656817Sralph 					mrp->byteCount = 1;
68756817Sralph 			} else if (mrp->byteCount == 2) {
68856817Sralph 				/*
68956817Sralph 				 * The second mouse report byte (delta x).
69056817Sralph 				 */
69156817Sralph 				mrp->dx = cc;
69256817Sralph 			} else if (mrp->byteCount == 3) {
69356817Sralph 				/*
69456817Sralph 				 * The final mouse report byte (delta y).
69556817Sralph 				 */
69656817Sralph 				mrp->dy = cc;
69756817Sralph 				mrp->byteCount = 0;
69856817Sralph 				if (mrp->dx != 0 || mrp->dy != 0) {
69956817Sralph 					/*
70056817Sralph 					 * If the mouse moved,
70156817Sralph 					 * post a motion event.
70256817Sralph 					 */
70356817Sralph 					(*sccMouseEvent)(mrp);
70456817Sralph 				}
70556817Sralph 				(*sccMouseButtons)(mrp);
70656817Sralph 			}
70756817Sralph 			continue;
70856817Sralph 		}
70956817Sralph 		if (!(tp->t_state & TS_ISOPEN)) {
71056817Sralph 			wakeup((caddr_t)&tp->t_rawq);
71156817Sralph #ifdef PORTSELECTOR
71256817Sralph 			if (!(tp->t_state & TS_WOPEN))
71356817Sralph #endif
71456817Sralph 				continue;
71556817Sralph 		}
716*57234Sralph 		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
717*57234Sralph 			rr2 == SCC_RR2_B_RECV_SPECIAL) {
718*57234Sralph 			if (rr1 & SCC_RR1_PARITY_ERR)
719*57234Sralph 				cc |= TTY_PE;
720*57234Sralph 			if (rr1 & SCC_RR1_FRAME_ERR)
721*57234Sralph 				cc |= TTY_FE;
72256817Sralph 		}
72356817Sralph 		(*linesw[tp->t_line].l_rint)(cc, tp);
72456817Sralph 	    } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {
72556817Sralph 		chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?
72656817Sralph 			SCC_CHANNEL_A : SCC_CHANNEL_B;
72756817Sralph 		SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_EXT_IP);
72856817Sralph 		scc_modem_intr(unit | chan);
72956817Sralph 	    }
73056817Sralph 	}
73156817Sralph }
73256817Sralph 
73356817Sralph void
73456817Sralph sccstart(tp)
73556817Sralph 	register struct tty *tp;
73656817Sralph {
73756817Sralph 	register struct pdma *dp;
73856817Sralph 	register scc_regmap_t *regs;
73956817Sralph 	register struct scc_softc *sc;
74056817Sralph 	register int cc, chan;
74156817Sralph 	u_char temp;
742*57234Sralph 	int s, sendone;
74356817Sralph 
74456817Sralph 	dp = (struct pdma *)tp->t_addr;
74556817Sralph 	regs = (scc_regmap_t *)dp->p_addr;
74656817Sralph 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
74756817Sralph 	s = spltty();
74856817Sralph 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
74956817Sralph 		goto out;
75056817Sralph 	if (tp->t_outq.c_cc <= tp->t_lowat) {
75156817Sralph 		if (tp->t_state & TS_ASLEEP) {
75256817Sralph 			tp->t_state &= ~TS_ASLEEP;
75356817Sralph 			wakeup((caddr_t)&tp->t_outq);
75456817Sralph 		}
75556817Sralph 		selwakeup(&tp->t_wsel);
75656817Sralph 	}
75756817Sralph 	if (tp->t_outq.c_cc == 0)
75856817Sralph 		goto out;
75956817Sralph 	/* handle console specially */
76056817Sralph 	if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
76156817Sralph 		while (tp->t_outq.c_cc > 0) {
76256817Sralph 			cc = getc(&tp->t_outq) & 0x7f;
76356817Sralph 			cnputc(cc);
76456817Sralph 		}
76556817Sralph 		/*
76656817Sralph 		 * After we flush the output queue we may need to wake
76756817Sralph 		 * up the process that made the output.
76856817Sralph 		 */
76956817Sralph 		if (tp->t_outq.c_cc <= tp->t_lowat) {
77056817Sralph 			if (tp->t_state & TS_ASLEEP) {
77156817Sralph 				tp->t_state &= ~TS_ASLEEP;
77256817Sralph 				wakeup((caddr_t)&tp->t_outq);
77356817Sralph 			}
77456817Sralph 			selwakeup(&tp->t_wsel);
77556817Sralph 		}
77656817Sralph 		goto out;
77756817Sralph 	}
77856817Sralph 	if (tp->t_flags & (RAW|LITOUT))
77956817Sralph 		cc = ndqb(&tp->t_outq, 0);
78056817Sralph 	else {
78156817Sralph 		cc = ndqb(&tp->t_outq, 0200);
78256817Sralph 		if (cc == 0) {
78356817Sralph 			cc = getc(&tp->t_outq);
78456817Sralph 			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
78556817Sralph 			tp->t_state |= TS_TIMEOUT;
78656817Sralph 			goto out;
78756817Sralph 		}
78856817Sralph 	}
78956817Sralph 	tp->t_state |= TS_BUSY;
79056817Sralph 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
79156817Sralph 	dp->p_end += cc;
79256817Sralph 
79356817Sralph 	/*
79456817Sralph 	 * Enable transmission and send the first char, as required.
79556817Sralph 	 */
79656817Sralph 	chan = SCCLINE(tp->t_dev);
797*57234Sralph 	SCC_READ_REG(regs, chan, SCC_RR0, temp);
798*57234Sralph 	sendone = (temp & SCC_RR0_TX_EMPTY);
79956817Sralph 	SCC_READ_REG(regs, chan, SCC_RR15, temp);
80056817Sralph 	temp |= SCC_WR15_TX_UNDERRUN_IE;
80156817Sralph 	SCC_WRITE_REG(regs, chan, SCC_WR15, temp);
80256817Sralph 	temp = sc->scc_wreg[chan].wr1 | SCC_WR1_TX_IE;
80356817Sralph 	SCC_WRITE_REG(regs, chan, SCC_WR1, temp);
80456817Sralph 	sc->scc_wreg[chan].wr1 = temp;
805*57234Sralph 	if (sendone) {
80656817Sralph #ifdef DIAGNOSTIC
80756817Sralph 		if (cc == 0)
80856817Sralph 			panic("sccstart: No chars");
80956817Sralph #endif
81056817Sralph 		SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
81156817Sralph 	}
81256817Sralph 	MachEmptyWriteBuffer();
81356817Sralph out:
81456817Sralph 	splx(s);
81556817Sralph }
81656817Sralph 
81756817Sralph /*
81856817Sralph  * Stop output on a line.
81956817Sralph  */
82056817Sralph /*ARGSUSED*/
82156817Sralph sccstop(tp, flag)
82256817Sralph 	register struct tty *tp;
82356817Sralph {
82456817Sralph 	register struct pdma *dp;
82556817Sralph 	register int s;
82656817Sralph 
82756817Sralph 	dp = (struct pdma *)tp->t_addr;
82856817Sralph 	s = spltty();
82956817Sralph 	if (tp->t_state & TS_BUSY) {
83056817Sralph 		dp->p_end = dp->p_mem;
83156817Sralph 		if (!(tp->t_state & TS_TTSTOP))
83256817Sralph 			tp->t_state |= TS_FLUSH;
83356817Sralph 	}
83456817Sralph 	splx(s);
83556817Sralph }
83656817Sralph 
83756817Sralph sccmctl(dev, bits, how)
83856817Sralph 	dev_t dev;
83956817Sralph 	int bits, how;
84056817Sralph {
84156817Sralph 	register struct scc_softc *sc;
84256817Sralph 	register scc_regmap_t *regs;
84356817Sralph 	register int line, mbits;
84456817Sralph 	register u_char value;
84556817Sralph 	int s;
84656817Sralph 
84756817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
84856817Sralph 	line = SCCLINE(dev);
84956817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
85056817Sralph 	s = spltty();
85156817Sralph 	/*
85256817Sralph 	 * only channel B has modem control, however the DTR and RTS
85356817Sralph 	 * pins on the comm port are wired to the DTR and RTS A channel
85456817Sralph 	 * signals.
85556817Sralph 	 */
85656817Sralph 	mbits = DML_DTR | DML_DSR | DML_CAR;
85756817Sralph 	if (line == SCC_CHANNEL_B) {
85856817Sralph 		if (sc->scc_wreg[SCC_CHANNEL_A].wr5 & SCC_WR5_DTR)
85956817Sralph 			mbits = DML_DTR | DML_DSR;
86056817Sralph 		else
86156817Sralph 			mbits = 0;
86256817Sralph 		SCC_READ_REG_ZERO(regs, SCC_CHANNEL_B, value);
86356817Sralph 		if (value & SCC_RR0_DCD)
86456817Sralph 			mbits |= DML_CAR;
86556817Sralph 	}
86656817Sralph 	switch (how) {
86756817Sralph 	case DMSET:
86856817Sralph 		mbits = bits;
86956817Sralph 		break;
87056817Sralph 
87156817Sralph 	case DMBIS:
87256817Sralph 		mbits |= bits;
87356817Sralph 		break;
87456817Sralph 
87556817Sralph 	case DMBIC:
87656817Sralph 		mbits &= ~bits;
87756817Sralph 		break;
87856817Sralph 
87956817Sralph 	case DMGET:
88056817Sralph 		(void) splx(s);
88156817Sralph 		return (mbits);
88256817Sralph 	}
88356817Sralph 	if (line == SCC_CHANNEL_B) {
88456817Sralph 		if (mbits & DML_DTR)
88556817Sralph 			sc->scc_wreg[SCC_CHANNEL_A].wr5 |= SCC_WR5_DTR;
88656817Sralph 		else
88756817Sralph 			sc->scc_wreg[SCC_CHANNEL_A].wr5 &= ~SCC_WR5_DTR;
88856817Sralph 		SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR5,
88956817Sralph 			sc->scc_wreg[SCC_CHANNEL_A].wr5);
89056817Sralph 	}
89156817Sralph 	if ((mbits & DML_DTR) && (sc->scc_softCAR & (1 << line)))
89256817Sralph 		scc_tty[minor(dev)].t_state |= TS_CARR_ON;
89356817Sralph 	(void) splx(s);
89456817Sralph 	return (mbits);
89556817Sralph }
89656817Sralph 
89756817Sralph /*
89856817Sralph  * Check for carrier transition.
89956817Sralph  */
90056817Sralph static void
90156817Sralph scc_modem_intr(dev)
90256817Sralph 	dev_t dev;
90356817Sralph {
90456817Sralph 	register scc_regmap_t *regs;
90556817Sralph 	register struct scc_softc *sc;
90656817Sralph 	register struct tty *tp;
90756817Sralph 	register int car, chan;
90856817Sralph 	register u_char value;
90956817Sralph 	int s;
91056817Sralph 
91156817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
91256817Sralph 	tp = &scc_tty[minor(dev)];
91356817Sralph 	regs = (scc_regmap_t *)((struct pdma *)tp->t_addr)->p_addr;
91456817Sralph 	chan = SCCLINE(dev);
91556817Sralph 	if (chan == SCC_CHANNEL_A)
91656817Sralph 		return;
91756817Sralph 	s = spltty();
91856817Sralph 	if (sc->scc_softCAR & (1 << chan))
91956817Sralph 		car = 1;
92056817Sralph 	else {
92156817Sralph 		SCC_READ_REG_ZERO(regs, chan, value);
92256817Sralph 		car = value & SCC_RR0_DCD;
92356817Sralph 	}
92456817Sralph 	if (car) {
92556817Sralph 		/* carrier present */
92656817Sralph 		if (!(tp->t_state & TS_CARR_ON))
92756817Sralph 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
92856817Sralph 	} else if (tp->t_state & TS_CARR_ON)
92956817Sralph 		(void)(*linesw[tp->t_line].l_modem)(tp, 0);
93056817Sralph 	splx(s);
93156817Sralph }
93256817Sralph 
93356817Sralph /*
93456817Sralph  * Get a char off the appropriate line via. a busy wait loop.
93556817Sralph  */
93656817Sralph int
93756817Sralph sccGetc(dev)
93856817Sralph 	dev_t dev;
93956817Sralph {
94056817Sralph 	register scc_regmap_t *regs;
94156817Sralph 	register int c, line;
94256817Sralph 	register u_char value;
94356817Sralph 	int s;
94456817Sralph 
94556817Sralph 	line = SCCLINE(dev);
94656817Sralph 	regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;
94756817Sralph 	if (!regs)
94856817Sralph 		return (0);
94956817Sralph 	s = spltty();
95056817Sralph 	for (;;) {
95156817Sralph 		SCC_READ_REG(regs, line, SCC_RR0, value);
95256817Sralph 		if (value & SCC_RR0_RX_AVAIL) {
95356817Sralph 			SCC_READ_REG(regs, line, SCC_RR1, value);
95456817Sralph 			if (value & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN |
95556817Sralph 				SCC_RR1_FRAME_ERR)) {
95656817Sralph 				SCC_WRITE_REG(regs, line, SCC_WR0, SCC_RESET_ERROR);
95756817Sralph 				SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
95856817Sralph 					SCC_RESET_HIGHEST_IUS);
95956817Sralph 			} else {
96056817Sralph 				SCC_READ_DATA(regs, line, c);
96156817Sralph 				SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
96256817Sralph 					SCC_RESET_HIGHEST_IUS);
96356817Sralph 				splx(s);
96456817Sralph 				return (c & 0xff);
96556817Sralph 			}
96656817Sralph 		} else
96756817Sralph 			DELAY(10);
96856817Sralph 	}
96956817Sralph }
97056817Sralph 
97156817Sralph /*
97256817Sralph  * Send a char on a port, via a busy wait loop.
97356817Sralph  */
97456817Sralph void
97556817Sralph sccPutc(dev, c)
97656817Sralph 	dev_t dev;
97756817Sralph 	int c;
97856817Sralph {
97956817Sralph 	register scc_regmap_t *regs;
980*57234Sralph 	register int line;
98156817Sralph 	register u_char value;
98256817Sralph 	int s;
98356817Sralph 
98456817Sralph 	s = spltty();
98556817Sralph 	line = SCCLINE(dev);
98656817Sralph 	regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;
987*57234Sralph 
98856817Sralph 	/*
98956817Sralph 	 * Wait for transmitter to be not busy.
99056817Sralph 	 */
99156817Sralph 	do {
99256817Sralph 		SCC_READ_REG(regs, line, SCC_RR0, value);
993*57234Sralph 		if (value & SCC_RR0_TX_EMPTY)
994*57234Sralph 			break;
995*57234Sralph 		DELAY(100);
996*57234Sralph 	} while (1);
997*57234Sralph 
998*57234Sralph 	/*
999*57234Sralph 	 * Send the char.
1000*57234Sralph 	 */
1001*57234Sralph 	SCC_WRITE_DATA(regs, line, c);
1002*57234Sralph 	MachEmptyWriteBuffer();
100356817Sralph 	splx(s);
100456817Sralph }
100556817Sralph #endif /* NSCC */
1006