xref: /csrg-svn/sys/pmax/dev/scc.c (revision 69799)
156817Sralph /*-
263207Sbostic  * Copyright (c) 1992, 1993
363207Sbostic  *	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*69799Sralph  *	@(#)scc.c	8.3 (Berkeley) 06/02/95
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  */
sccprobe(cp)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_dev = (dev_t)((cp->pmax_unit << 1) | cntr);
17756817Sralph 		pdp++, tp++;
17856817Sralph 	}
17956817Sralph 	sc->scc_softCAR = cp->pmax_flags | 0x2;
18056817Sralph 
18156817Sralph 	/* reset chip */
18256817Sralph 	sccreset(sc);
18356817Sralph 
18456817Sralph 	/*
18556817Sralph 	 * Special handling for consoles.
18656817Sralph 	 */
18756817Sralph 	if (cn_tab.cn_screen) {
18856817Sralph 		if (cn_tab.cn_kbdgetc == sccGetc) {
18958793Sralph 			if (cp->pmax_unit == 1) {
19056817Sralph 				s = spltty();
19156817Sralph 				ctty.t_dev = makedev(SCCDEV, SCCKBD_PORT);
19256817Sralph 				cterm.c_cflag = CS8;
19356817Sralph 				cterm.c_ospeed = cterm.c_ispeed = 4800;
19456817Sralph 				(void) sccparam(&ctty, &cterm);
19558793Sralph 				DELAY(10000);
19658793Sralph #ifdef notyet
19758793Sralph 				/*
19858793Sralph 				 * For some reason doing this hangs the 3min
19958793Sralph 				 * during booting. Fortunately the keyboard
20058793Sralph 				 * works ok without it.
20158793Sralph 				 */
20256817Sralph 				KBDReset(ctty.t_dev, sccPutc);
20358793Sralph #endif
20458793Sralph 				DELAY(10000);
20556817Sralph 				splx(s);
20658793Sralph 			} else if (cp->pmax_unit == 0) {
20756817Sralph 				s = spltty();
20856817Sralph 				ctty.t_dev = makedev(SCCDEV, SCCMOUSE_PORT);
20956817Sralph 				cterm.c_cflag = CS8 | PARENB | PARODD;
21056817Sralph 				cterm.c_ospeed = cterm.c_ispeed = 4800;
21156817Sralph 				(void) sccparam(&ctty, &cterm);
21258793Sralph 				DELAY(10000);
21356817Sralph 				MouseInit(ctty.t_dev, sccPutc, sccGetc);
21458793Sralph 				DELAY(10000);
21556817Sralph 				splx(s);
21656817Sralph 			}
21756817Sralph 		}
21856817Sralph 	} else if (SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit) {
21956817Sralph 		s = spltty();
22056817Sralph 		ctty.t_dev = cn_tab.cn_dev;
22156817Sralph 		cterm.c_cflag = CS8;
22256817Sralph 		cterm.c_ospeed = cterm.c_ispeed = 9600;
22356817Sralph 		(void) sccparam(&ctty, &cterm);
22457234Sralph 		DELAY(1000);
22556817Sralph 		cn_tab.cn_disabled = 0;
22656817Sralph 		splx(s);
22756817Sralph 	}
22857234Sralph 	printf("scc%d at nexus0 csr 0x%x priority %d\n",
22957234Sralph 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
23056817Sralph 	return (1);
23156817Sralph }
23256817Sralph 
23356817Sralph /*
23456817Sralph  * Reset the chip.
23556817Sralph  */
23656817Sralph static void
sccreset(sc)23756817Sralph sccreset(sc)
23856817Sralph 	register struct scc_softc *sc;
23956817Sralph {
24056817Sralph 	register scc_regmap_t *regs;
24156817Sralph 	register u_char val;
24256817Sralph 
24356817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
24456817Sralph 	/*
24556817Sralph 	 * Chip once-only initialization
24656817Sralph 	 *
24756817Sralph 	 * NOTE: The wiring we assume is the one on the 3min:
24856817Sralph 	 *
24956817Sralph 	 *	out	A-TxD	-->	TxD	keybd or mouse
25056817Sralph 	 *	in	A-RxD	-->	RxD	keybd or mouse
25156817Sralph 	 *	out	A-DTR~	-->	DTR	comm
25256817Sralph 	 *	out	A-RTS~	-->	RTS	comm
25356817Sralph 	 *	in	A-CTS~	-->	SI	comm
25456817Sralph 	 *	in	A-DCD~	-->	RI	comm
25556817Sralph 	 *	in	A-SYNCH~-->	DSR	comm
25656817Sralph 	 *	out	B-TxD	-->	TxD	comm
25756817Sralph 	 *	in	B-RxD	-->	RxD	comm
25856817Sralph 	 *	in	B-RxC	-->	TRxCB	comm
25956817Sralph 	 *	in	B-TxC	-->	RTxCB	comm
26056817Sralph 	 *	out	B-RTS~	-->	SS	comm
26156817Sralph 	 *	in	B-CTS~	-->	CTS	comm
26256817Sralph 	 *	in	B-DCD~	-->	CD	comm
26356817Sralph 	 */
26456817Sralph 	SCC_INIT_REG(regs, SCC_CHANNEL_A);
26556817Sralph 	SCC_INIT_REG(regs, SCC_CHANNEL_B);
26656817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET);
26756817Sralph 	DELAY(50000);	/*enough ? */
26856817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, 0);
26956817Sralph 
27056817Sralph 	/* program the interrupt vector */
27156817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0);
27256817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0);
27356817Sralph 	SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS);
27456817Sralph 
27556817Sralph 	/* timing base defaults */
27656817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16;
27756817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16;
27856817Sralph 
27956817Sralph 	/* enable DTR, RTS and SS */
28056817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS;
28156817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR;
28256817Sralph 
28356817Sralph 	/* baud rates */
28456817Sralph 	val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC;
28556817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr14 = val;
28656817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr14 = val;
28756817Sralph 
28856817Sralph 	/* interrupt conditions */
28956817Sralph 	val =	SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE |
29057234Sralph 		SCC_WR1_EXT_IE;
29156817Sralph 	sc->scc_wreg[SCC_CHANNEL_A].wr1 = val;
29256817Sralph 	sc->scc_wreg[SCC_CHANNEL_B].wr1 = val;
29356817Sralph }
29456817Sralph 
sccopen(dev,flag,mode,p)29556817Sralph sccopen(dev, flag, mode, p)
29656817Sralph 	dev_t dev;
29756817Sralph 	int flag, mode;
29856817Sralph 	struct proc *p;
29956817Sralph {
30056817Sralph 	register struct scc_softc *sc;
30156817Sralph 	register struct tty *tp;
30256817Sralph 	register int unit, line;
30356817Sralph 	int s, error = 0;
30456817Sralph 
30556817Sralph 	unit = SCCUNIT(dev);
30656817Sralph 	if (unit >= NSCC)
30756817Sralph 		return (ENXIO);
30856817Sralph 	line = SCCLINE(dev);
30956817Sralph 	sc = &scc_softc[unit];
31056817Sralph 	if (sc->scc_pdma[line].p_addr == (void *)0)
31156817Sralph 		return (ENXIO);
31256817Sralph 	tp = &scc_tty[minor(dev)];
31356817Sralph 	tp->t_oproc = sccstart;
31456817Sralph 	tp->t_param = sccparam;
31556817Sralph 	tp->t_dev = dev;
31656817Sralph 	if ((tp->t_state & TS_ISOPEN) == 0) {
31756817Sralph 		tp->t_state |= TS_WOPEN;
31856817Sralph 		ttychars(tp);
31956817Sralph #ifndef PORTSELECTOR
32056817Sralph 		if (tp->t_ispeed == 0) {
32156817Sralph #endif
32256817Sralph 			tp->t_iflag = TTYDEF_IFLAG;
32356817Sralph 			tp->t_oflag = TTYDEF_OFLAG;
32456817Sralph 			tp->t_cflag = TTYDEF_CFLAG;
32556817Sralph 			tp->t_lflag = LFLAG;
32656817Sralph 			tp->t_ispeed = tp->t_ospeed = ISPEED;
32756817Sralph #ifdef PORTSELECTOR
32856817Sralph 			tp->t_cflag |= HUPCL;
32956817Sralph #else
33056817Sralph 		}
33156817Sralph #endif
33256817Sralph 		(void) sccparam(tp, &tp->t_termios);
33356817Sralph 		ttsetwater(tp);
33456817Sralph 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
33556817Sralph 		return (EBUSY);
33656817Sralph 	(void) sccmctl(dev, DML_DTR, DMSET);
33756817Sralph 	s = spltty();
33856817Sralph 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
33956817Sralph 	       !(tp->t_state & TS_CARR_ON)) {
34056817Sralph 		tp->t_state |= TS_WOPEN;
34156817Sralph 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
34256817Sralph 		    ttopen, 0))
34356817Sralph 			break;
34456817Sralph 	}
34556817Sralph 	splx(s);
34656817Sralph 	if (error)
34756817Sralph 		return (error);
34856817Sralph 	return ((*linesw[tp->t_line].l_open)(dev, tp));
34956817Sralph }
35056817Sralph 
35156817Sralph /*ARGSUSED*/
sccclose(dev,flag,mode,p)35256817Sralph sccclose(dev, flag, mode, p)
35356817Sralph 	dev_t dev;
35456817Sralph 	int flag, mode;
35556817Sralph 	struct proc *p;
35656817Sralph {
35756817Sralph 	register struct scc_softc *sc = &scc_softc[SCCUNIT(dev)];
35856817Sralph 	register struct tty *tp;
35956817Sralph 	register int bit, line;
36056817Sralph 
36156817Sralph 	tp = &scc_tty[minor(dev)];
36256817Sralph 	line = SCCLINE(dev);
36356817Sralph 	if (sc->scc_wreg[line].wr5 & SCC_WR5_SEND_BREAK) {
36456817Sralph 		sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
36556817Sralph 		ttyoutput(0, tp);
36656817Sralph 	}
36756817Sralph 	(*linesw[tp->t_line].l_close)(tp, flag);
36856817Sralph 	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
36956817Sralph 	    !(tp->t_state & TS_ISOPEN))
37056817Sralph 		(void) sccmctl(dev, 0, DMSET);
37156817Sralph 	return (ttyclose(tp));
37256817Sralph }
37356817Sralph 
sccread(dev,uio,flag)37456817Sralph sccread(dev, uio, flag)
37556817Sralph 	dev_t dev;
37656817Sralph 	struct uio *uio;
37756817Sralph {
37856817Sralph 	register struct tty *tp;
37956817Sralph 
38056817Sralph 	tp = &scc_tty[minor(dev)];
38156817Sralph 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
38256817Sralph }
38356817Sralph 
sccwrite(dev,uio,flag)38456817Sralph sccwrite(dev, uio, flag)
38556817Sralph 	dev_t dev;
38656817Sralph 	struct uio *uio;
38756817Sralph {
38856817Sralph 	register struct tty *tp;
38956817Sralph 
39056817Sralph 	tp = &scc_tty[minor(dev)];
39156817Sralph 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
39256817Sralph }
39356817Sralph 
39456817Sralph /*ARGSUSED*/
sccioctl(dev,cmd,data,flag,p)39556817Sralph sccioctl(dev, cmd, data, flag, p)
39656817Sralph 	dev_t dev;
397*69799Sralph 	u_long cmd;
39856817Sralph 	caddr_t data;
39956817Sralph 	int flag;
40056817Sralph 	struct proc *p;
40156817Sralph {
40256817Sralph 	register struct scc_softc *sc;
40356817Sralph 	register struct tty *tp;
40456817Sralph 	int error, line;
40556817Sralph 
40656817Sralph 	tp = &scc_tty[minor(dev)];
40756817Sralph 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
40856817Sralph 	if (error >= 0)
40956817Sralph 		return (error);
41056817Sralph 	error = ttioctl(tp, cmd, data, flag);
41156817Sralph 	if (error >= 0)
41256817Sralph 		return (error);
41356817Sralph 
41456817Sralph 	line = SCCLINE(dev);
41556817Sralph 	sc = &scc_softc[SCCUNIT(dev)];
41656817Sralph 	switch (cmd) {
41756817Sralph 
41856817Sralph 	case TIOCSBRK:
41956817Sralph 		sc->scc_wreg[line].wr5 |= SCC_WR5_SEND_BREAK;
42056817Sralph 		ttyoutput(0, tp);
42156817Sralph 		break;
42256817Sralph 
42356817Sralph 	case TIOCCBRK:
42456817Sralph 		sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
42556817Sralph 		ttyoutput(0, tp);
42656817Sralph 		break;
42756817Sralph 
42856817Sralph 	case TIOCSDTR:
42956817Sralph 		(void) sccmctl(dev, DML_DTR|DML_RTS, DMBIS);
43056817Sralph 		break;
43156817Sralph 
43256817Sralph 	case TIOCCDTR:
43356817Sralph 		(void) sccmctl(dev, DML_DTR|DML_RTS, DMBIC);
43456817Sralph 		break;
43556817Sralph 
43656817Sralph 	case TIOCMSET:
43756817Sralph 		(void) sccmctl(dev, *(int *)data, DMSET);
43856817Sralph 		break;
43956817Sralph 
44056817Sralph 	case TIOCMBIS:
44156817Sralph 		(void) sccmctl(dev, *(int *)data, DMBIS);
44256817Sralph 		break;
44356817Sralph 
44456817Sralph 	case TIOCMBIC:
44556817Sralph 		(void) sccmctl(dev, *(int *)data, DMBIC);
44656817Sralph 		break;
44756817Sralph 
44856817Sralph 	case TIOCMGET:
44956817Sralph 		*(int *)data = sccmctl(dev, 0, DMGET);
45056817Sralph 		break;
45156817Sralph 
45256817Sralph 	default:
45356817Sralph 		return (ENOTTY);
45456817Sralph 	}
45556817Sralph 	return (0);
45656817Sralph }
45756817Sralph 
sccparam(tp,t)45856817Sralph sccparam(tp, t)
45956817Sralph 	register struct tty *tp;
46056817Sralph 	register struct termios *t;
46156817Sralph {
46256817Sralph 	register struct scc_softc *sc;
46356817Sralph 	register scc_regmap_t *regs;
46456817Sralph 	register int line;
46556817Sralph 	register u_char value, wvalue;
46656817Sralph 	register int cflag = t->c_cflag;
46756817Sralph 	int ospeed;
46856817Sralph 
46956817Sralph         if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
47056817Sralph                 return (EINVAL);
47156817Sralph 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
47256817Sralph 	line = SCCLINE(tp->t_dev);
47356817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
47456817Sralph 	ospeed = ttspeedtab(t->c_ospeed, sccspeedtab);
47556817Sralph         if (ospeed < 0)
47656817Sralph                 return (EINVAL);
47756817Sralph         /* and copy to tty */
47856817Sralph         tp->t_ispeed = t->c_ispeed;
47956817Sralph         tp->t_ospeed = t->c_ospeed;
48056817Sralph         tp->t_cflag = cflag;
48156817Sralph 
48256817Sralph 	/*
48356817Sralph 	 * Handle console specially.
48456817Sralph 	 */
48556817Sralph 	if (cn_tab.cn_screen) {
48656817Sralph 		if (minor(tp->t_dev) == SCCKBD_PORT) {
48756817Sralph 			cflag = CS8;
48856817Sralph 			ospeed = ttspeedtab(4800, sccspeedtab);
48956817Sralph 		} else if (minor(tp->t_dev) == SCCMOUSE_PORT) {
49056817Sralph 			cflag = CS8 | PARENB | PARODD;
49156817Sralph 			ospeed = ttspeedtab(4800, sccspeedtab);
49256817Sralph 		}
49356817Sralph 	} else if (tp->t_dev == cn_tab.cn_dev) {
49456817Sralph 		cflag = CS8;
49556817Sralph 		ospeed = ttspeedtab(9600, sccspeedtab);
49656817Sralph 	}
49756817Sralph 	if (ospeed == 0) {
49856817Sralph 		(void) sccmctl(tp->t_dev, 0, DMSET);	/* hang up line */
49956817Sralph 		return (0);
50056817Sralph 	}
50156817Sralph 
50256817Sralph 	/* reset line */
50356817Sralph 	if (line == SCC_CHANNEL_A)
50456817Sralph 		value = SCC_WR9_RESET_CHA_A;
50556817Sralph 	else
50656817Sralph 		value = SCC_WR9_RESET_CHA_B;
50756817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, value);
50856817Sralph 	DELAY(25);
50956817Sralph 
51056817Sralph 	/* stop bits, normally 1 */
51156817Sralph 	value = sc->scc_wreg[line].wr4 & 0xf0;
51256817Sralph 	if (cflag & CSTOPB)
51356817Sralph 		value |= SCC_WR4_2_STOP;
51456817Sralph 	else
51556817Sralph 		value |= SCC_WR4_1_STOP;
51656817Sralph 	if ((cflag & PARODD) == 0)
51756817Sralph 		value |= SCC_WR4_EVEN_PARITY;
51856817Sralph 	if (cflag & PARENB)
51956817Sralph 		value |= SCC_WR4_PARITY_ENABLE;
52056817Sralph 
52156817Sralph 	/* set it now, remember it must be first after reset */
52256817Sralph 	sc->scc_wreg[line].wr4 = value;
52356817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR4, value);
52456817Sralph 
52556817Sralph 	/* vector again */
52656817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR2, 0xf0);
52756817Sralph 
52856817Sralph 	/* clear break, keep rts dtr */
52956817Sralph 	wvalue = sc->scc_wreg[line].wr5 & (SCC_WR5_DTR|SCC_WR5_RTS);
53056817Sralph 	switch (cflag & CSIZE) {
53156817Sralph 	case CS5:
53256817Sralph 		value = SCC_WR3_RX_5_BITS;
53356817Sralph 		wvalue |= SCC_WR5_TX_5_BITS;
53456817Sralph 		break;
53556817Sralph 	case CS6:
53656817Sralph 		value = SCC_WR3_RX_6_BITS;
53756817Sralph 		wvalue |= SCC_WR5_TX_6_BITS;
53856817Sralph 		break;
53956817Sralph 	case CS7:
54056817Sralph 		value = SCC_WR3_RX_7_BITS;
54156817Sralph 		wvalue |= SCC_WR5_TX_7_BITS;
54256817Sralph 		break;
54356817Sralph 	case CS8:
54456817Sralph 	default:
54556817Sralph 		value = SCC_WR3_RX_8_BITS;
54656817Sralph 		wvalue |= SCC_WR5_TX_8_BITS;
54756817Sralph 	};
54856817Sralph 	sc->scc_wreg[line].wr3 = value;
54956817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR3, value);
55056817Sralph 	sc->scc_wreg[line].wr5 = wvalue;
55156817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR5, wvalue);
55256817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR6, 0);
55356817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR7, 0);
55456817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, SCC_WR9_VIS);
55556817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR10, 0);
55656817Sralph 	value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR |
55756817Sralph 		SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR;
55856817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR11, value);
55956817Sralph 	SCC_SET_TIMING_BASE(regs, line, ospeed);
56056817Sralph 	value = sc->scc_wreg[line].wr14;
56156817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR14, value);
56256817Sralph 	value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE;
56356817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR15, value);
56456817Sralph 
56556817Sralph 	/* and now the enables */
56656817Sralph 	value = sc->scc_wreg[line].wr3 | SCC_WR3_RX_ENABLE;
56756817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR3, value);
56856817Sralph 	value = sc->scc_wreg[line].wr5 | SCC_WR5_TX_ENABLE;
56956817Sralph 	sc->scc_wreg[line].wr5 = value;
57056817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR5, value);
57156817Sralph 
57256817Sralph 	/* master inter enable */
57356817Sralph 	value = SCC_WR9_MASTER_IE | SCC_WR9_VIS;
57456817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR9, value);
57556817Sralph 	SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1);
57656817Sralph 	MachEmptyWriteBuffer();
57756817Sralph 	return (0);
57856817Sralph }
57956817Sralph 
58056817Sralph /*
58156817Sralph  * Check for interrupts from all devices.
58256817Sralph  */
58356817Sralph void
sccintr(unit)58456817Sralph sccintr(unit)
58556817Sralph 	register int unit;
58656817Sralph {
58756817Sralph 	register scc_regmap_t *regs;
58856817Sralph 	register struct tty *tp;
58956817Sralph 	register struct pdma *dp;
59056817Sralph 	register struct scc_softc *sc;
59156817Sralph 	register int cc, chan, rr1, rr2, rr3;
59256817Sralph 	int overrun = 0;
59356817Sralph 
59456817Sralph 	sc = &scc_softc[unit];
59556817Sralph 	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
59656817Sralph 	unit <<= 1;
59756817Sralph 	for (;;) {
59856817Sralph 	    SCC_READ_REG(regs, SCC_CHANNEL_B, SCC_RR2, rr2);
59956817Sralph 	    rr2 = SCC_RR2_STATUS(rr2);
60056817Sralph 	    /* are we done yet ? */
60156817Sralph 	    if (rr2 == 6) {	/* strange, distinguished value */
60256817Sralph 		SCC_READ_REG(regs, SCC_CHANNEL_A, SCC_RR3, rr3);
60356817Sralph 		if (rr3 == 0)
60456817Sralph 			return;
60556817Sralph 	    }
60656817Sralph 
60756817Sralph 	    SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS);
60856817Sralph 	    if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {
60956817Sralph 		chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?
61056817Sralph 			SCC_CHANNEL_A : SCC_CHANNEL_B;
61156817Sralph 		tp = &scc_tty[unit | chan];
61264979Smckusick 		dp = &sc->scc_pdma[chan];
61356817Sralph 		if (dp->p_mem < dp->p_end) {
61456817Sralph 			SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
61556817Sralph 			MachEmptyWriteBuffer();
61656817Sralph 		} else {
61756817Sralph 			tp->t_state &= ~TS_BUSY;
61856817Sralph 			if (tp->t_state & TS_FLUSH)
61956817Sralph 				tp->t_state &= ~TS_FLUSH;
62056817Sralph 			else {
62156817Sralph 				ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
62256817Sralph 				dp->p_end = dp->p_mem = tp->t_outq.c_cf;
62356817Sralph 			}
62456817Sralph 			if (tp->t_line)
62556817Sralph 				(*linesw[tp->t_line].l_start)(tp);
62656817Sralph 			else
62756817Sralph 				sccstart(tp);
62856817Sralph 			if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
62956817Sralph 				SCC_READ_REG(regs, chan, SCC_RR15, cc);
63056817Sralph 				cc &= ~SCC_WR15_TX_UNDERRUN_IE;
63156817Sralph 				SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
63256817Sralph 				cc = sc->scc_wreg[chan].wr1 & ~SCC_WR1_TX_IE;
63356817Sralph 				SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
63456817Sralph 				sc->scc_wreg[chan].wr1 = cc;
63556817Sralph 				MachEmptyWriteBuffer();
63656817Sralph 			}
63756817Sralph 		}
63857234Sralph 	    } else if (rr2 == SCC_RR2_A_RECV_DONE ||
63957234Sralph 		rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||
64057234Sralph 		rr2 == SCC_RR2_B_RECV_SPECIAL) {
64157234Sralph 		if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)
64257234Sralph 			chan = SCC_CHANNEL_A;
64357234Sralph 		else
64457234Sralph 			chan = SCC_CHANNEL_B;
64557234Sralph 		tp = &scc_tty[unit | chan];
64657234Sralph 		SCC_READ_DATA(regs, chan, cc);
64757234Sralph 		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
64857234Sralph 			rr2 == SCC_RR2_B_RECV_SPECIAL) {
64957234Sralph 			SCC_READ_REG(regs, chan, SCC_RR1, rr1);
65057234Sralph 			SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_ERROR);
65157234Sralph 			if ((rr1 & SCC_RR1_RX_OVERRUN) && overrun == 0) {
65257234Sralph 				log(LOG_WARNING, "scc%d,%d: silo overflow\n",
65357234Sralph 					unit >> 1, chan);
65457234Sralph 				overrun = 1;
65557234Sralph 			}
65657234Sralph 		}
65756817Sralph 
65856817Sralph 		/*
65956817Sralph 		 * Keyboard needs special treatment.
66056817Sralph 		 */
66156817Sralph 		if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
66256817Sralph #ifdef KADB
66356817Sralph 			if (cc == LK_DO) {
66456817Sralph 				spl0();
66556817Sralph 				kdbpanic();
66656817Sralph 				return;
66756817Sralph 			}
66856817Sralph #endif
66956817Sralph #ifdef DEBUG
67056817Sralph 			debugChar = cc;
67156817Sralph #endif
67256817Sralph 			if (sccDivertXInput) {
67356817Sralph 				(*sccDivertXInput)(cc);
67456817Sralph 				continue;
67556817Sralph 			}
67656817Sralph 			if ((cc = kbdMapChar(cc)) < 0)
67756817Sralph 				continue;
67856817Sralph 		/*
67956817Sralph 		 * Now for mousey
68056817Sralph 		 */
68156817Sralph 		} else if (tp == &scc_tty[SCCMOUSE_PORT] && sccMouseButtons) {
68256817Sralph 			register MouseReport *mrp;
68356817Sralph 			static MouseReport currentRep;
68456817Sralph 
68556817Sralph 			mrp = &currentRep;
68656817Sralph 			mrp->byteCount++;
68756817Sralph 			if (cc & MOUSE_START_FRAME) {
68856817Sralph 				/*
68956817Sralph 				 * The first mouse report byte (button state).
69056817Sralph 				 */
69156817Sralph 				mrp->state = cc;
69256817Sralph 				if (mrp->byteCount > 1)
69356817Sralph 					mrp->byteCount = 1;
69456817Sralph 			} else if (mrp->byteCount == 2) {
69556817Sralph 				/*
69656817Sralph 				 * The second mouse report byte (delta x).
69756817Sralph 				 */
69856817Sralph 				mrp->dx = cc;
69956817Sralph 			} else if (mrp->byteCount == 3) {
70056817Sralph 				/*
70156817Sralph 				 * The final mouse report byte (delta y).
70256817Sralph 				 */
70356817Sralph 				mrp->dy = cc;
70456817Sralph 				mrp->byteCount = 0;
70556817Sralph 				if (mrp->dx != 0 || mrp->dy != 0) {
70656817Sralph 					/*
70756817Sralph 					 * If the mouse moved,
70856817Sralph 					 * post a motion event.
70956817Sralph 					 */
71056817Sralph 					(*sccMouseEvent)(mrp);
71156817Sralph 				}
71256817Sralph 				(*sccMouseButtons)(mrp);
71356817Sralph 			}
71456817Sralph 			continue;
71556817Sralph 		}
71656817Sralph 		if (!(tp->t_state & TS_ISOPEN)) {
71756817Sralph 			wakeup((caddr_t)&tp->t_rawq);
71856817Sralph #ifdef PORTSELECTOR
71956817Sralph 			if (!(tp->t_state & TS_WOPEN))
72056817Sralph #endif
72156817Sralph 				continue;
72256817Sralph 		}
72357234Sralph 		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
72457234Sralph 			rr2 == SCC_RR2_B_RECV_SPECIAL) {
72557234Sralph 			if (rr1 & SCC_RR1_PARITY_ERR)
72657234Sralph 				cc |= TTY_PE;
72757234Sralph 			if (rr1 & SCC_RR1_FRAME_ERR)
72857234Sralph 				cc |= TTY_FE;
72956817Sralph 		}
73056817Sralph 		(*linesw[tp->t_line].l_rint)(cc, tp);
73156817Sralph 	    } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {
73256817Sralph 		chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?
73356817Sralph 			SCC_CHANNEL_A : SCC_CHANNEL_B;
73456817Sralph 		SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_EXT_IP);
73556817Sralph 		scc_modem_intr(unit | chan);
73656817Sralph 	    }
73756817Sralph 	}
73856817Sralph }
73956817Sralph 
74056817Sralph void
sccstart(tp)74156817Sralph sccstart(tp)
74256817Sralph 	register struct tty *tp;
74356817Sralph {
74456817Sralph 	register struct pdma *dp;
74556817Sralph 	register scc_regmap_t *regs;
74656817Sralph 	register struct scc_softc *sc;
74756817Sralph 	register int cc, chan;
74856817Sralph 	u_char temp;
74957234Sralph 	int s, sendone;
75056817Sralph 
75164979Smckusick 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
75264979Smckusick 	dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];
75356817Sralph 	regs = (scc_regmap_t *)dp->p_addr;
75456817Sralph 	s = spltty();
75556817Sralph 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
75656817Sralph 		goto out;
75756817Sralph 	if (tp->t_outq.c_cc <= tp->t_lowat) {
75856817Sralph 		if (tp->t_state & TS_ASLEEP) {
75956817Sralph 			tp->t_state &= ~TS_ASLEEP;
76056817Sralph 			wakeup((caddr_t)&tp->t_outq);
76156817Sralph 		}
76256817Sralph 		selwakeup(&tp->t_wsel);
76356817Sralph 	}
76456817Sralph 	if (tp->t_outq.c_cc == 0)
76556817Sralph 		goto out;
76656817Sralph 	/* handle console specially */
76756817Sralph 	if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
76856817Sralph 		while (tp->t_outq.c_cc > 0) {
76956817Sralph 			cc = getc(&tp->t_outq) & 0x7f;
77056817Sralph 			cnputc(cc);
77156817Sralph 		}
77256817Sralph 		/*
77356817Sralph 		 * After we flush the output queue we may need to wake
77456817Sralph 		 * up the process that made the output.
77556817Sralph 		 */
77656817Sralph 		if (tp->t_outq.c_cc <= tp->t_lowat) {
77756817Sralph 			if (tp->t_state & TS_ASLEEP) {
77856817Sralph 				tp->t_state &= ~TS_ASLEEP;
77956817Sralph 				wakeup((caddr_t)&tp->t_outq);
78056817Sralph 			}
78156817Sralph 			selwakeup(&tp->t_wsel);
78256817Sralph 		}
78356817Sralph 		goto out;
78456817Sralph 	}
78556817Sralph 	if (tp->t_flags & (RAW|LITOUT))
78656817Sralph 		cc = ndqb(&tp->t_outq, 0);
78756817Sralph 	else {
78856817Sralph 		cc = ndqb(&tp->t_outq, 0200);
78956817Sralph 		if (cc == 0) {
79056817Sralph 			cc = getc(&tp->t_outq);
79156817Sralph 			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
79256817Sralph 			tp->t_state |= TS_TIMEOUT;
79356817Sralph 			goto out;
79456817Sralph 		}
79556817Sralph 	}
79656817Sralph 	tp->t_state |= TS_BUSY;
79756817Sralph 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
79856817Sralph 	dp->p_end += cc;
79956817Sralph 
80056817Sralph 	/*
80156817Sralph 	 * Enable transmission and send the first char, as required.
80256817Sralph 	 */
80356817Sralph 	chan = SCCLINE(tp->t_dev);
80457234Sralph 	SCC_READ_REG(regs, chan, SCC_RR0, temp);
80557234Sralph 	sendone = (temp & SCC_RR0_TX_EMPTY);
80656817Sralph 	SCC_READ_REG(regs, chan, SCC_RR15, temp);
80756817Sralph 	temp |= SCC_WR15_TX_UNDERRUN_IE;
80856817Sralph 	SCC_WRITE_REG(regs, chan, SCC_WR15, temp);
80956817Sralph 	temp = sc->scc_wreg[chan].wr1 | SCC_WR1_TX_IE;
81056817Sralph 	SCC_WRITE_REG(regs, chan, SCC_WR1, temp);
81156817Sralph 	sc->scc_wreg[chan].wr1 = temp;
81257234Sralph 	if (sendone) {
81356817Sralph #ifdef DIAGNOSTIC
81456817Sralph 		if (cc == 0)
81556817Sralph 			panic("sccstart: No chars");
81656817Sralph #endif
81756817Sralph 		SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
81856817Sralph 	}
81956817Sralph 	MachEmptyWriteBuffer();
82056817Sralph out:
82156817Sralph 	splx(s);
82256817Sralph }
82356817Sralph 
82456817Sralph /*
82556817Sralph  * Stop output on a line.
82656817Sralph  */
82756817Sralph /*ARGSUSED*/
sccstop(tp,flag)82856817Sralph sccstop(tp, flag)
82956817Sralph 	register struct tty *tp;
83056817Sralph {
83156817Sralph 	register struct pdma *dp;
83264979Smckusick 	register struct scc_softc *sc;
83356817Sralph 	register int s;
83456817Sralph 
83564979Smckusick 	sc = &scc_softc[SCCUNIT(tp->t_dev)];
83664979Smckusick 	dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];
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 
sccmctl(dev,bits,how)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
scc_modem_intr(dev)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 	chan = SCCLINE(dev);
92364979Smckusick 	regs = (scc_regmap_t *)sc->scc_pdma[chan].p_addr;
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
sccGetc(dev)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
sccPutc(dev,c)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