xref: /csrg-svn/sys/news3400/sio/scc.c (revision 57184)
153905Smckusick /*
253905Smckusick  * Copyright (c) 1992 The Regents of the University of California.
353905Smckusick  * All rights reserved.
453905Smckusick  *
553905Smckusick  * This code is derived from software contributed to Berkeley by
653905Smckusick  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
753905Smckusick  *
853905Smckusick  * %sccs.include.redist.c%
953905Smckusick  *
1053905Smckusick  * from: $Hdr: scc.c,v 4.300 91/06/09 06:44:53 root Rel41 $ SONY
1153905Smckusick  *
12*57184Sutashiro  *	@(#)scc.c	7.2 (Berkeley) 12/17/92
1353905Smckusick  */
1453905Smckusick 
1553905Smckusick /*
1653905Smckusick  * LH8530 SCC (serial communication controller) driver
1753905Smckusick  *
1853905Smckusick  * NOTE: This driver is available only for news700/1200/1700/3400.
1953905Smckusick  *
2053905Smckusick  * Any code and mechanism in this module may not be used
2153905Smckusick  * in any form without permissions.  COPYRIGHT (C) 1989-
2253905Smckusick  * SONY  Corporation,   Super Microsystems Group (SMSG),
2353905Smckusick  * Work Station Division, all rights RESERVED.
2453905Smckusick  */
2553905Smckusick 
26*57184Sutashiro #include <machine/fix_machine_type.h>
27*57184Sutashiro #include <machine/adrsmap.h>
2853905Smckusick 
2953905Smckusick #include "rs.h"
3053905Smckusick 
31*57184Sutashiro #include <sys/param.h>
32*57184Sutashiro #include <sys/ioctl.h>
33*57184Sutashiro #include <sys/tty.h>
34*57184Sutashiro #include <sys/malloc.h>
3553905Smckusick 
36*57184Sutashiro #include <news3400/sio/sccparam.h>
37*57184Sutashiro #include <news3400/sio/sccreg.h>
38*57184Sutashiro #include <news3400/sio/scc.h>
39*57184Sutashiro #include <news3400/sio/scc.conf>
4053905Smckusick 
4153905Smckusick #define	PROBE_DATA	0x55
4253905Smckusick 
4353905Smckusick #ifdef mips
4453905Smckusick #define	VOLATILE	volatile
4553905Smckusick #else
4653905Smckusick #define	VOLATILE
4753905Smckusick #endif
4853905Smckusick 
4953905Smckusick int	tty00_is_console = 0;
5053905Smckusick 
5153905Smckusick #define	SCC_BUFSIZE	256
5253905Smckusick 
5353905Smckusick char	scc_buf[2][SCC_BUFSIZE];
5453905Smckusick 
5553905Smckusick scc_open(chan)
5653905Smckusick 	int chan;
5753905Smckusick {
5853905Smckusick 	register Scc_channel *scc = &sccsw[chan];
5953905Smckusick 	register int s;
6053905Smckusick 
6153905Smckusick 	s = splscc();
6253905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
6353905Smckusick 		scc_init(chan);
6453905Smckusick 		if (chan <= SCC_REMOTE1)
6553905Smckusick 			scc->r_dma.dma_addr = scc_buf[chan];
6653905Smckusick 		else
6753905Smckusick 			scc->r_dma.dma_addr =
6853905Smckusick 				malloc(SCC_BUFSIZE, M_DEVBUF, M_WAITOK);
6953905Smckusick 		scc->r_dma.dma_count = 0;
7053905Smckusick 		scc->scc_status |= CHAN_ACTIVE;
7153905Smckusick 	}
7253905Smckusick 	(void) splx(s);
7353905Smckusick 	return (0);
7453905Smckusick }
7553905Smckusick 
7653905Smckusick scc_probe(chan)
7753905Smckusick 	register int chan;
7853905Smckusick {
7953905Smckusick 	VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
8053905Smckusick 	int s, temp, probe;
8153905Smckusick 
8253905Smckusick 	if (badaddr(port, 1))
8353905Smckusick 		return (0);
8453905Smckusick 	s = splscc();
8553905Smckusick 	temp = scc_read_reg(chan, RR12);
8653905Smckusick 	scc_write_reg(chan, WR12, PROBE_DATA);
8753905Smckusick 	probe = scc_read_reg(chan, RR12);
8853905Smckusick 	scc_write_reg(chan, WR12, temp);
8953905Smckusick 	(void) splx(s);
9053905Smckusick 	return (probe == PROBE_DATA);
9153905Smckusick }
9253905Smckusick 
9353905Smckusick scc_getc(chan)
9453905Smckusick 	int chan;
9553905Smckusick {
9653905Smckusick 	VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
9753905Smckusick 	int c;
9853905Smckusick 
9953905Smckusick 	if (port->ctrl & R0_RxCA) {
10053905Smckusick 		SCCWAIT;
10153905Smckusick 		c = port->data;
10253905Smckusick 		SCCWAIT;
10353905Smckusick 		return (c);
10453905Smckusick 	}
10553905Smckusick 	SCCWAIT;
10653905Smckusick 	return (-1);
10753905Smckusick }
10853905Smckusick 
10953905Smckusick #ifndef notdef
11053905Smckusick scc_putc(chan, c)
11153905Smckusick 	int chan, c;
11253905Smckusick {
11353905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
11453905Smckusick 
11553905Smckusick 	while ((port->ctrl & R0_TxBE) == 0)
11653905Smckusick 		SCCWAIT;
11753905Smckusick 	SCCWAIT;
11853905Smckusick 	port->data = c;
11953905Smckusick 	SCCWAIT;
12053905Smckusick }
12153905Smckusick #else
12253905Smckusick scc_putc(chan, c)
12353905Smckusick         int chan, c;
12453905Smckusick {
12553905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
12653905Smckusick 	register VOLATILE u_char *ctrl = &sccsw[chan].scc_port->ctrl;
12753905Smckusick 	register VOLATILE u_char *data = &sccsw[chan].scc_port->data;
12853905Smckusick 
12953905Smckusick         SCCWAIT;
13053905Smckusick         while ((*ctrl & R0_TxBE) == 0) {
13153905Smckusick                 SCCWAIT;
13253905Smckusick         }
13353905Smckusick         SCCWAIT;
13453905Smckusick 
13553905Smckusick         *ctrl = W0_RES_TxINT;
13653905Smckusick         SCCWAIT;
13753905Smckusick         *data = (char)(c & 0xff);
13853905Smckusick         SCCWAIT;
13953905Smckusick         scc_write_reg(chan, WR1, W1_RxINT_ALL|W1_TxINTE|W1_EXTINTE|W1_PARITY);
14053905Smckusick         SCCWAIT;
14153905Smckusick }
14253905Smckusick #endif
14353905Smckusick 
14453905Smckusick scc_init(chan)
14553905Smckusick 	int chan;
14653905Smckusick {
14753905Smckusick 	register VOLATILE struct scc_reg *port;
14853905Smckusick 	register char *data;
14953905Smckusick 	register int i;
15053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
15153905Smckusick 	int s;
15253905Smckusick 
15353905Smckusick 	s = splscc();
15453905Smckusick 	data = scc->scc_init;
15553905Smckusick 	port = scc->scc_port;
15653905Smckusick 	for (i = 0; i < N_INITDATA; i++) {
15753905Smckusick 		port->ctrl = *data++;
15853905Smckusick 		SCCWAIT;
15953905Smckusick 	}
16053905Smckusick 	scc_write_reg(chan, WR2, scc->scc_vec & ~0x0f);
16153905Smckusick /* KU:XXX
16253905Smckusick This must be bug because scc->scc_param is not initialized yet.
16353905Smckusick 	scc_set_param(chan, scc->scc_param);
16453905Smckusick */
16553905Smckusick 	(void) splx(s);
16653905Smckusick }
16753905Smckusick 
16853905Smckusick #define	vec_to_scc(vec)		((((vec) - SCCVEC0) >> 3) & 0x000f)
16953905Smckusick #define	vec_to_chan(vec)	scc2chan[vec_to_scc(vec)]
17053905Smckusick 
17153905Smckusick int scc2chan[] = {
17253905Smckusick #ifdef news700
17353905Smckusick 	0,	1,
17453905Smckusick #else /* news700 */
17553905Smckusick 	1,	0,
17653905Smckusick #endif /* news700 */
17753905Smckusick 	3,	2,
17853905Smckusick 	5,	4,
17953905Smckusick 	7,	6,
18053905Smckusick 	9,	8
18153905Smckusick };
18253905Smckusick 
18353905Smckusick #ifdef news700
18453905Smckusick #define	OFF		0x80
18553905Smckusick 
18653905Smckusick scc_rint(vec)
18753905Smckusick 	int vec;
18853905Smckusick {
18953905Smckusick 	int chan = vec_to_chan(vec);
19053905Smckusick 	Scc_channel *scc = &sccsw[chan];
19153905Smckusick 	register struct scc_reg *port = scc->scc_port;
19253905Smckusick 	register int c;
19353905Smckusick #if NMS > 0
19453905Smckusick 	extern int _ms_helper();
19553905Smckusick #endif /* NMS > 0 */
19653905Smckusick #if NBM > 0
19753905Smckusick 	extern int kb_softint();
19853905Smckusick #endif /* NBM > 0 */
19953905Smckusick 
20053905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
20153905Smckusick 		scc_reset(chan);
20253905Smckusick 		goto out;
20353905Smckusick 	}
20453905Smckusick 	while (port->ctrl & R0_RxCA) {
20553905Smckusick 		SCCWAIT;
20653905Smckusick 		c = port->data;
20753905Smckusick 		SCCWAIT;
20853905Smckusick 		switch (chan) {
20953905Smckusick 
21053905Smckusick 		case SCC_MOUSE:
21153905Smckusick #if NMS > 0
21253905Smckusick 			if (xputc(c, SCC_MOUSE) < 0)
21353905Smckusick 				printf("mouse queue overflow\n");
21453905Smckusick 			softcall(_ms_helper, (caddr_t)0);
21553905Smckusick #endif
21653905Smckusick 			break;
21753905Smckusick 
21853905Smckusick 		case SCC_KEYBOARD:
21953905Smckusick #if NBM > 0
22053905Smckusick 			if (xputc(c, SCC_KEYBOARD) < 0)
22153905Smckusick 				printf("keyboard queue overflow\n");
22253905Smckusick 			softcall(kb_softint, (caddr_t)0);
22353905Smckusick #endif
22453905Smckusick 			break;
22553905Smckusick 
22653905Smckusick 		default:
22753905Smckusick 			printf("kb or ms stray intr\n");
22853905Smckusick 			break;
22953905Smckusick 		}
23053905Smckusick 		SCCWAIT;
23153905Smckusick 	}
23253905Smckusick out:
23353905Smckusick 	port->ctrl = W0_RES_IUS;
23453905Smckusick 	SCCWAIT;
23553905Smckusick }
23653905Smckusick #else /* news700 */
23753905Smckusick scc_rint(vec)
23853905Smckusick 	int vec;
23953905Smckusick {
24053905Smckusick 	int chan = vec_to_chan(vec);
24153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
24253905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
24353905Smckusick 	register int c;
24453905Smckusick 
24553905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
24653905Smckusick 		scc_reset(chan);
24753905Smckusick 		goto out;
24853905Smckusick 	}
24953905Smckusick 	if (scc->scc_status & LINE_BREAK){
25053905Smckusick 		scc->scc_status &= ~LINE_BREAK;
25153905Smckusick 		c = port->data;
25253905Smckusick 		SCCWAIT;
25353905Smckusick 	}
25453905Smckusick 	while (port->ctrl & R0_RxCA) {
25553905Smckusick 		SCCWAIT;
25653905Smckusick 		c = port->data;
25753905Smckusick 		SCCWAIT;
25853905Smckusick #if NRS > 0
25953905Smckusick 		scc_pdma(chan, c);
26053905Smckusick #endif
26153905Smckusick 	}
26253905Smckusick 	SCCWAIT;
26353905Smckusick out:
26453905Smckusick 	port->ctrl = W0_RES_IUS;
26553905Smckusick 	SCCWAIT;
26653905Smckusick }
26753905Smckusick #endif /* news700 */
26853905Smckusick 
26953905Smckusick #if NRS > 0
27053905Smckusick scc_enable(chan)
27153905Smckusick 	int chan;
27253905Smckusick {
27353905Smckusick 	register Scc_channel *scc = &sccsw[chan];
27453905Smckusick 	int n;
27553905Smckusick 	int s;
27653905Smckusick 
27753905Smckusick 	s = splscc();
27853905Smckusick 	if ((n = scc->r_dma.dma_count) > 0) {
27953905Smckusick 		scc->r_dma.dma_count = 0;
28053905Smckusick 		rsrint(chan, scc->r_dma.dma_addr, n);
28153905Smckusick 	} else
28253905Smckusick 		scc->scc_status |= ENABLE;
28353905Smckusick 	(void) splx(s);
28453905Smckusick }
28553905Smckusick 
28653905Smckusick scc_pdma(chan, c)
28753905Smckusick 	int chan;
28853905Smckusick 	int c;
28953905Smckusick {
29053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
29153905Smckusick 	int n;
29253905Smckusick 
29353905Smckusick 	if (scc->r_dma.dma_count >= SCC_BUFSIZE)
29453905Smckusick 		printf("rs%d soft fifo overflow\n", chan);
29553905Smckusick 	else
29653905Smckusick 		scc->r_dma.dma_addr[scc->r_dma.dma_count++] = c;
29753905Smckusick 	if (scc->scc_status & ENABLE || scc->r_dma.dma_count >= SCC_BUFSIZE) {
29853905Smckusick 		scc->scc_status &= ~ENABLE;
29953905Smckusick 		n = scc->r_dma.dma_count;
30053905Smckusick 		scc->r_dma.dma_count = 0;
30153905Smckusick 		rsrint(chan, scc->r_dma.dma_addr, n);
30253905Smckusick 	}
30353905Smckusick }
30453905Smckusick #endif /* NRS > 0 */
30553905Smckusick 
30653905Smckusick scc_xint(vec)
30753905Smckusick 	int vec;
30853905Smckusick {
30953905Smckusick 	int chan = vec_to_chan(vec);
31053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
31153905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
31253905Smckusick 
31353905Smckusick 	if (scc->scc_status & OSTOP)
31453905Smckusick 		scc->scc_status &= ~(OACTIVE|OSTOP);
31553905Smckusick 	if (scc->scc_status & OFLUSH) {
31653905Smckusick 		scc->x_dma.dma_count = 0;
31753905Smckusick 		scc->scc_status &= ~(OACTIVE|OFLUSH);
31853905Smckusick 	}
31953905Smckusick 	if ((scc->scc_status & OACTIVE) && (scc->x_dma.dma_count > 0)) {
32053905Smckusick 		port->data = *(scc->x_dma.dma_addr)++;
32153905Smckusick 		SCCWAIT;
32253905Smckusick 		scc->x_dma.dma_count--;
32353905Smckusick 	} else {
32453905Smckusick 		port->ctrl = W0_RES_TxINT;
32553905Smckusick 		SCCWAIT;
32653905Smckusick 		scc->scc_status &= ~OACTIVE;
32753905Smckusick #if NRS > 0
32853905Smckusick 		if (scc->x_dma.dma_count == 0)
32953905Smckusick 			rsxint(chan);
33053905Smckusick #endif
33153905Smckusick 	}
33253905Smckusick 	port->ctrl = W0_RES_IUS;
33353905Smckusick 	SCCWAIT;
33453905Smckusick }
33553905Smckusick 
33653905Smckusick scc_sint(vec)
33753905Smckusick 	int vec;
33853905Smckusick {
33953905Smckusick 	int chan = vec_to_chan(vec);
34053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
34153905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
34253905Smckusick 	register int status;
34353905Smckusick 	register int param = 0;
34453905Smckusick 
34553905Smckusick 	port->ctrl = W0_RES_EXT;
34653905Smckusick 	SCCWAIT;
34753905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
34853905Smckusick 		scc_reset(chan);
34953905Smckusick 		goto out;
35053905Smckusick 	}
35153905Smckusick 	status = port->ctrl;
35253905Smckusick 	SCCWAIT;
35353905Smckusick 	if (status & R0_DCD)
35453905Smckusick 		param |= DCD;
35553905Smckusick 	if (status & R0_CTS)
35653905Smckusick 		param |= CTS;
35753905Smckusick 	if (status & R0_BREAK){
35853905Smckusick 		param |= RBREAK;
35953905Smckusick 		scc->scc_status |= LINE_BREAK;
36053905Smckusick 	}
36153905Smckusick 	if ((scc->scc_param & (DCD|CTS|RBREAK)) != param) {
36253905Smckusick 		scc->scc_param = (scc->scc_param & ~(DCD|CTS|RBREAK)) | param;
36353905Smckusick #if NRS > 0
36453905Smckusick 		rssint(chan, scc->scc_param);
36553905Smckusick #endif
36653905Smckusick 	}
36753905Smckusick out:
36853905Smckusick 	port->ctrl = W0_RES_IUS;
36953905Smckusick 	SCCWAIT;
37053905Smckusick }
37153905Smckusick 
37253905Smckusick scc_cint(vec)
37353905Smckusick 	int vec;
37453905Smckusick {
37553905Smckusick 	int chan = vec_to_chan(vec);
37653905Smckusick 	register Scc_channel *scc = &sccsw[chan];
37753905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
37853905Smckusick 	register int status;
37953905Smckusick 	int c;
38053905Smckusick 
38153905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
38253905Smckusick 		scc_reset(chan);
38353905Smckusick 		goto out;
38453905Smckusick 	}
38553905Smckusick 	status = scc_read_reg(chan, RR1);
38653905Smckusick 	if (status & R1_CRC)
38753905Smckusick 		scc->scc_param |= FRAMING_ERROR;
38853905Smckusick 	if (status & R1_OVRUN) {
38953905Smckusick 		if ((scc->scc_param & OVERRUN_ERROR) == 0) {
39053905Smckusick 			scc->scc_param |= OVERRUN_ERROR;
39153905Smckusick #if NRS > 0
39253905Smckusick 			rssint(chan, scc->scc_param);
39353905Smckusick #endif /* NRS > 0 */
39453905Smckusick 		}
39553905Smckusick 	}
39653905Smckusick 	if (status & R1_PARITY) {
39753905Smckusick 		scc->scc_param |= SCC_PARITY_ERROR;
39853905Smckusick 		while (port->ctrl & R0_RxCA) {
39953905Smckusick 			SCCWAIT;
40053905Smckusick 			c = port->data;
40153905Smckusick 			SCCWAIT;
40253905Smckusick #if NRS > 0
40353905Smckusick 			if (scc->scc_param & NOCHECK)
40453905Smckusick 				scc_pdma(chan, c);
40553905Smckusick #endif
40653905Smckusick 		}
40753905Smckusick 		SCCWAIT;
40853905Smckusick 	}
40953905Smckusick out:
41053905Smckusick 	port->ctrl = W0_RES_ERROR;
41153905Smckusick 	SCCWAIT;
41253905Smckusick 	port->ctrl = W0_RES_IUS;
41353905Smckusick 	SCCWAIT;
41453905Smckusick }
41553905Smckusick 
41653905Smckusick scc_write_reg(chan, reg, data)
41753905Smckusick 	int chan, reg, data;
41853905Smckusick {
41953905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
42053905Smckusick 
42153905Smckusick 	port->ctrl = reg;
42253905Smckusick 	SCCWAIT;
42353905Smckusick 	port->ctrl = data;
42453905Smckusick 	SCCWAIT;
42553905Smckusick }
42653905Smckusick 
42753905Smckusick scc_read_reg(chan, reg)
42853905Smckusick 	int chan, reg;
42953905Smckusick {
43053905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
43153905Smckusick 	int result;
43253905Smckusick 
43353905Smckusick 	port->ctrl = reg;
43453905Smckusick 	SCCWAIT;
43553905Smckusick 	result = port->ctrl;
43653905Smckusick 	SCCWAIT;
43753905Smckusick 	return (result);
43853905Smckusick }
43953905Smckusick 
44053905Smckusick #ifdef news1700
44153905Smckusick #define	DSRA	0x20
44253905Smckusick #define	RIA	0x04
44353905Smckusick #define	DSRB	0x02
44453905Smckusick #define	RIB	0x01
44553905Smckusick 
44653905Smckusick #define	DSRC	0x01
44753905Smckusick #define	RIC	0x02
44853905Smckusick #define	DSRD	0x04
44953905Smckusick #define	RID	0x08
45053905Smckusick #define	DSRE	0x10
45153905Smckusick #define	RIE	0x20
45253905Smckusick #define	DSRF	0x40
45353905Smckusick #define	RIF	0x80
45453905Smckusick #endif /* news1700 */
45553905Smckusick 
45653905Smckusick #ifdef news1200
45753905Smckusick #define	DSRA	0x08
45853905Smckusick #define	RIA	0x04
45953905Smckusick #define	DSRB	0x02
46053905Smckusick #define	RIB	0x01
46153905Smckusick #endif /* news1200 */
46253905Smckusick 
46353905Smckusick #ifdef news3400
46453905Smckusick #define	DSRA	0x01
46553905Smckusick #define	RIA	0x02
46653905Smckusick #define	DSRB	0x04
46753905Smckusick #define	RIB	0x08
46853905Smckusick 
46953905Smckusick #define	DSRC	0x01
47053905Smckusick #define	RIC	0x02
47153905Smckusick #define	DSRD	0x04
47253905Smckusick #define	RID	0x08
47353905Smckusick #define	DSRE	0x10
47453905Smckusick #define	RIE	0x20
47553905Smckusick #define	DSRF	0x40
47653905Smckusick #define	RIF	0x80
47753905Smckusick #endif /* news3400 */
47853905Smckusick 
47953905Smckusick struct ri_dsr {
48053905Smckusick 	char	*status;
48153905Smckusick 	int	ri;
48253905Smckusick 	int	dsr;
48353905Smckusick } ri_dsr[] = {
48453905Smckusick #ifdef news700
48553905Smckusick 	{ (char *)0, 0, 0 }
48653905Smckusick #else /* news700 */
48753905Smckusick 	{ (char *)SCC_STATUS0, RIA, DSRA },
48853905Smckusick 	{ (char *)SCC_STATUS0, RIB, DSRB },
48953905Smckusick #if !defined(news1200) && !defined(news3200)
49053905Smckusick 	{ (char *)SCC_STATUS1, RIC, DSRC },
49153905Smckusick 	{ (char *)SCC_STATUS1, RID, DSRD },
49253905Smckusick 	{ (char *)SCC_STATUS1, RIE, DSRE },
49353905Smckusick 	{ (char *)SCC_STATUS1, RIF, DSRF },
49453905Smckusick 	{ (char *)SCC_STATUS2, RIC, DSRC },
49553905Smckusick 	{ (char *)SCC_STATUS2, RID, DSRD },
49653905Smckusick 	{ (char *)SCC_STATUS2, RIE, DSRE },
49753905Smckusick 	{ (char *)SCC_STATUS2, RIF, DSRF }
49853905Smckusick #endif /* !news1200 && !news3200 */
49953905Smckusick #endif /* news700 */
50053905Smckusick };
50153905Smckusick 
50253905Smckusick get_ri_dsr(chan)
50353905Smckusick 	int chan;
50453905Smckusick {
50553905Smckusick 	register struct ri_dsr *p;
50653905Smckusick 	register int status, param;
50753905Smckusick 
50853905Smckusick 	param = 0;
50953905Smckusick #ifndef news700
51053905Smckusick 	p = &ri_dsr[chan];
51153905Smckusick 	status = *p->status;
51253905Smckusick 	if ((status & p->ri) == 0)
51353905Smckusick 		param |= RI;
51453905Smckusick 	if ((status & p->dsr) == 0)
51553905Smckusick 		param |= DSR;
51653905Smckusick #endif /* !news700 */
51753905Smckusick 	return (param);
51853905Smckusick }
51953905Smckusick 
52053905Smckusick #ifdef news700
52153905Smckusick /*
52253905Smckusick  *	tc = floor(5000000 / 32 / baudrate - 2 + 0.5);
52353905Smckusick  */
52453905Smckusick static int tc0[] = {
52553905Smckusick 	0,		/* B0 */
52653905Smckusick 	3123,		/* B50 */
52753905Smckusick 	2081,		/* B75 */
52853905Smckusick 	1418,		/* B110 */
52953905Smckusick 	1164,		/* B134 */
53053905Smckusick 	1039,		/* B150 */
53153905Smckusick 	779,		/* B200 */
53253905Smckusick 	518,		/* B300 */
53353905Smckusick 	258,		/* B600 */
53453905Smckusick 	128,		/* B1200 */
53553905Smckusick 	84,		/* B1800 */
53653905Smckusick 	63,		/* B2400 */
53753905Smckusick 	30,		/* B4800 */
53853905Smckusick 	14,		/* B9600 */
53953905Smckusick 	14,		/* EXTA	*/
54053905Smckusick 	14		/* EXTB	*/
54153905Smckusick };
54253905Smckusick #endif /* news700 */
54353905Smckusick 
54453905Smckusick #ifdef news1700
54553905Smckusick /*
54653905Smckusick  *	tc0 = floor(4000000 / 32 / baudrate - 2 + 0.5);
54753905Smckusick  */
54853905Smckusick static int tc0[] = {
54953905Smckusick 	0,		/* B0 */
55053905Smckusick 	2498,		/* B50 */
55153905Smckusick 	1664,		/* B75 */
55253905Smckusick 	1134,		/* B110 */
55353905Smckusick 	930,		/* B134 */
55453905Smckusick 	831,		/* B150 */
55553905Smckusick 	623,		/* B200 */
55653905Smckusick 	414,		/* B300 */
55753905Smckusick 	206,		/* B600 */
55853905Smckusick 	102,		/* B1200 */
55953905Smckusick 	67,		/* B1800 */
56053905Smckusick 	50,		/* B2400 */
56153905Smckusick 	24,		/* B4800 */
56253905Smckusick 	11,		/* B9600 */
56353905Smckusick 	11,		/* EXTA (B9600)*/
56453905Smckusick 	11		/* EXTB (B9600)*/
56553905Smckusick };
56653905Smckusick #endif /* news1700 */
56753905Smckusick 
56853905Smckusick #if defined(news1200) || defined(news3400)
56953905Smckusick /*
57053905Smckusick  *	tc0 = floor(4915200 / 32 / baudrate - 2 + 0.5);
57153905Smckusick  */
57253905Smckusick static int tc0[] = {
57353905Smckusick 	0,		/* B0 */
57453905Smckusick 	3070,		/* B50 */
57553905Smckusick 	2046,		/* B75 */
57653905Smckusick 	1394,		/* B110 */
57753905Smckusick 	1144,		/* B134 */
57853905Smckusick 	1022,		/* B150 */
57953905Smckusick 	766,		/* B200 */
58053905Smckusick 	510,		/* B300 */
58153905Smckusick 	254,		/* B600 */
58253905Smckusick 	126,		/* B1200 */
58353905Smckusick 	83,		/* B1800 */
58453905Smckusick 	62,		/* B2400 */
58553905Smckusick 	30,		/* B4800 */
58653905Smckusick 	14,		/* B9600 */
58753905Smckusick 	6,		/* EXTA (B19200) */
58853905Smckusick 	2		/* EXTB (B38400) */
58953905Smckusick 	};
59053905Smckusick #endif /* news1200 || news3400 */
59153905Smckusick 
59253905Smckusick #ifndef news700
59353905Smckusick static int tc1[] = {
59453905Smckusick /*
59553905Smckusick  *	tc1 = floor(3686400 / 32 / baudrate - 2 + 0.5);
59653905Smckusick  */
59753905Smckusick 	0,		/* B0 */
59853905Smckusick 	2302,		/* B50 */
59953905Smckusick 	1534,		/* B75 */
60053905Smckusick 	1045,		/* B110 */
60153905Smckusick 	858,		/* B134 */
60253905Smckusick 	766,		/* B150 */
60353905Smckusick 	574,		/* B200 */
60453905Smckusick 	382,		/* B300 */
60553905Smckusick 	190,		/* B600 */
60653905Smckusick 	94,		/* B1200 */
60753905Smckusick 	62,		/* B1800 */
60853905Smckusick 	46,		/* B2400 */
60953905Smckusick 	22,		/* B4800 */
61053905Smckusick 	10,		/* B9600 */
61153905Smckusick 	4,		/* B19200 */
61253905Smckusick 	1,		/* B38400 */
61353905Smckusick };
61453905Smckusick #endif /* !news700 */
61553905Smckusick 
61653905Smckusick scc_set_param(chan, param)
61753905Smckusick 	int chan;
61853905Smckusick 	register int param;
61953905Smckusick {
62053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
62153905Smckusick 	register int bit, baud, *tc;
62253905Smckusick 	int s;
62353905Smckusick 
62453905Smckusick 	s = splscc();
62553905Smckusick 
62653905Smckusick 	/*
62753905Smckusick 	 * Baud rate / external clock
62853905Smckusick 	 */
62953905Smckusick 	if ((baud = param & BAUD_RATE) == EXTB && chan <= SCC_REMOTE1 &&
63053905Smckusick 	    param & EXTCLK_ENABLE) {
63153905Smckusick 		scc_write_reg(chan, WR11, W11_RxC_RTxC|W11_TxC_TRxC);
63253905Smckusick 		bit = W4_X1;
63353905Smckusick 	} else {
63453905Smckusick #ifdef news700
63553905Smckusick 		tc = tc0;
63653905Smckusick #else /* news700 */
63753905Smckusick 		tc = (chan <= SCC_REMOTE1) ? tc0 : tc1;
63853905Smckusick #endif /* news700 */
63953905Smckusick 		scc_write_reg(chan, WR11, W11_RxC_BRG|W11_TxC_BRG);
64053905Smckusick 		scc_write_reg(chan, WR12, tc[baud] & 0xff);
64153905Smckusick 		scc_write_reg(chan, WR13, tc[baud] >> 8);
64253905Smckusick 		bit = W4_X16;
64353905Smckusick 	}
64453905Smckusick 
64553905Smckusick 	/*
64653905Smckusick 	 * Clock mode / parity / stop bit
64753905Smckusick 	 */
64853905Smckusick 	if (param & PARITY) {
64953905Smckusick 		bit |= W4_PARITY;
65053905Smckusick 		if (param & EVEN)
65153905Smckusick 			bit |= W4_EVEN;
65253905Smckusick 	}
65353905Smckusick 	switch (param & STOPBIT) {
65453905Smckusick 
65553905Smckusick 	case STOP1:
65653905Smckusick 		bit |= W4_STOP1;
65753905Smckusick 		break;
65853905Smckusick 
65953905Smckusick 	case STOP1_5:
66053905Smckusick 		bit |= W4_STOP1_5;
66153905Smckusick 		break;
66253905Smckusick 
66353905Smckusick 	case STOP2:
66453905Smckusick 		bit |= W4_STOP2;
66553905Smckusick 		break;
66653905Smckusick 
66753905Smckusick 	}
66853905Smckusick 	scc_write_reg(chan, WR4, bit);
66953905Smckusick 
67053905Smckusick 	/*
67153905Smckusick 	 * Receiver enable / receive character size / auto enable
67253905Smckusick 	 */
67353905Smckusick 	bit = (param & RXE ? W3_RxE : 0);
67453905Smckusick 	switch (param & CHAR_SIZE) {
67553905Smckusick 
67653905Smckusick 	case C5BIT:
67753905Smckusick 		break;
67853905Smckusick 
67953905Smckusick 	case C6BIT:
68053905Smckusick 		bit |= W3_Rx6BIT;
68153905Smckusick 		break;
68253905Smckusick 
68353905Smckusick 	case C7BIT:
68453905Smckusick 		bit |= W3_Rx7BIT;
68553905Smckusick 		break;
68653905Smckusick 
68753905Smckusick 	case C8BIT:
68853905Smckusick 		bit |= W3_Rx8BIT;
68953905Smckusick 		break;
69053905Smckusick 	}
69153905Smckusick #ifdef AUTO_ENABLE
69253905Smckusick 	if (param & AUTO_ENABLE)
69353905Smckusick 		bit |= W3_AUTO;
69453905Smckusick #endif /* AUTO_ENABLE */
69553905Smckusick 	scc_write_reg(chan, WR3, bit);
69653905Smckusick 
69753905Smckusick 	/*
69853905Smckusick 	 * Transmitter enable / transmit character size / RTS / DTR / BREAK
69953905Smckusick 	 */
70053905Smckusick 	bit = (param & TXE ? W5_TxE : 0);
70153905Smckusick 	switch (param & CHAR_SIZE) {
70253905Smckusick 
70353905Smckusick 	case C5BIT:
70453905Smckusick 		break;
70553905Smckusick 
70653905Smckusick 	case C6BIT:
70753905Smckusick 		bit |= W5_Tx6BIT;
70853905Smckusick 		break;
70953905Smckusick 
71053905Smckusick 	case C7BIT:
71153905Smckusick 		bit |= W5_Tx7BIT;
71253905Smckusick 		break;
71353905Smckusick 
71453905Smckusick 	case C8BIT:
71553905Smckusick 		bit |= W5_Tx8BIT;
71653905Smckusick 		break;
71753905Smckusick 	}
71853905Smckusick 	if (param & RTS)
71953905Smckusick 		bit |= W5_RTS;
72053905Smckusick 	if (param & DTR)
72153905Smckusick 		bit |= W5_DTR;
72253905Smckusick 	if (param & XBREAK)
72353905Smckusick 		bit |= W5_BREAK;
72453905Smckusick 	scc_write_reg(chan, WR5, bit);
72553905Smckusick 	scc->scc_param = param;
72653905Smckusick 	(void) splx(s);
72753905Smckusick 	return (0);
72853905Smckusick }
72953905Smckusick 
73053905Smckusick scc_get_param(chan)
73153905Smckusick 	int chan;
73253905Smckusick {
73353905Smckusick 	register Scc_channel *scc = &sccsw[chan];
73453905Smckusick 
73553905Smckusick 	scc->scc_param = (scc->scc_param & ~(RI|DSR)) | get_ri_dsr(chan);
73653905Smckusick 	return (scc->scc_param);
73753905Smckusick }
73853905Smckusick 
73953905Smckusick scc_get_status(chan)
74053905Smckusick 	int chan;
74153905Smckusick {
74253905Smckusick 
74353905Smckusick 	return (sccsw[chan].scc_status);
74453905Smckusick }
74553905Smckusick 
74653905Smckusick scc_set_status(chan, stat)
74753905Smckusick 	int chan, stat;
74853905Smckusick {
74953905Smckusick 
75053905Smckusick 	sccsw[chan].scc_status = stat;
75153905Smckusick 
75253905Smckusick 	return (0);
75353905Smckusick }
75453905Smckusick 
75553905Smckusick scc_flush(chan)
75653905Smckusick 	int chan;
75753905Smckusick {
75853905Smckusick 	register Scc_channel *scc = &sccsw[chan];
75953905Smckusick 
76053905Smckusick 	if (scc->scc_status & OACTIVE)
76153905Smckusick 		scc->scc_status |= OFLUSH;
76253905Smckusick 	else if (scc->x_dma.dma_count > 0) {
76353905Smckusick 		scc->x_dma.dma_count = 0;
76453905Smckusick #if NRS > 0
76553905Smckusick 		rsxint(chan);
76653905Smckusick #endif
76753905Smckusick 	}
76853905Smckusick 	return (0);
76953905Smckusick }
77053905Smckusick 
77153905Smckusick scc_start(chan)
77253905Smckusick 	int chan;
77353905Smckusick {
77453905Smckusick 	register Scc_channel *scc = &sccsw[chan];
77553905Smckusick 
77653905Smckusick 	if ((scc->scc_status & OACTIVE) == 0 && scc->x_dma.dma_count > 0) {
77753905Smckusick 		scc->scc_port->data = *(scc->x_dma.dma_addr)++;
77853905Smckusick 		SCCWAIT;
77953905Smckusick 		scc->x_dma.dma_count--;
78053905Smckusick 		scc->scc_status |= OACTIVE;
78153905Smckusick 	}
78253905Smckusick 	return (0);
78353905Smckusick }
78453905Smckusick 
78553905Smckusick scc_stop(chan)
78653905Smckusick 	int chan;
78753905Smckusick {
78853905Smckusick 	register Scc_channel *scc = &sccsw[chan];
78953905Smckusick 
79053905Smckusick 	if (scc->scc_status & OACTIVE)
79153905Smckusick 		scc->scc_status |= OSTOP;
79253905Smckusick 	return (0);
79353905Smckusick }
79453905Smckusick 
79553905Smckusick scc_write(chan, buf, count)
79653905Smckusick 	int chan;
79753905Smckusick 	caddr_t buf;
79853905Smckusick 	int count;
79953905Smckusick {
80053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
80153905Smckusick 
80253905Smckusick 	if (count <= 0)
80353905Smckusick 		return (0);
80453905Smckusick 	scc->x_dma.dma_addr = buf;
80553905Smckusick 	scc->x_dma.dma_count = count;
80653905Smckusick 	scc_start(chan);
80753905Smckusick 	return (count);
80853905Smckusick }
80953905Smckusick 
81053905Smckusick scc_error_write(chan, buf, count)
81153905Smckusick 	int chan;
81253905Smckusick 	register char *buf;
81353905Smckusick 	register int count;
81453905Smckusick {
81553905Smckusick 	register int i;
81653905Smckusick 
81753905Smckusick 	for (i = 0; i < count; i++)
81853905Smckusick 		scc_putc(chan, *buf++);
81953905Smckusick 	return (i);
82053905Smckusick }
82153905Smckusick 
82253905Smckusick scc_reset(chan)
82353905Smckusick 	int chan;
82453905Smckusick {
82553905Smckusick 	register Scc_channel *scc = &sccsw[chan];
82653905Smckusick 
82753905Smckusick 	while (scc_getc(chan) != -1)
82853905Smckusick 		;
82953905Smckusick 	scc->scc_status &= ~CHAN_ACTIVE;
83053905Smckusick }
831