xref: /csrg-svn/sys/news3400/sio/scc.c (revision 63314)
153905Smckusick /*
2*63314Sbostic  * Copyright (c) 1992, 1993
3*63314Sbostic  *	The Regents of the University of California.  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*63314Sbostic  *	@(#)scc.c	8.1 (Berkeley) 06/11/93
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 
2657184Sutashiro #include <machine/adrsmap.h>
2753905Smckusick 
2853905Smckusick #include "rs.h"
2953905Smckusick 
3057184Sutashiro #include <sys/param.h>
3157184Sutashiro #include <sys/ioctl.h>
3257184Sutashiro #include <sys/tty.h>
3357184Sutashiro #include <sys/malloc.h>
3453905Smckusick 
3557184Sutashiro #include <news3400/sio/sccparam.h>
3657184Sutashiro #include <news3400/sio/sccreg.h>
3757184Sutashiro #include <news3400/sio/scc.h>
3857184Sutashiro #include <news3400/sio/scc.conf>
3953905Smckusick 
4053905Smckusick #define	PROBE_DATA	0x55
4153905Smckusick 
4253905Smckusick #ifdef mips
4353905Smckusick #define	VOLATILE	volatile
4453905Smckusick #else
4553905Smckusick #define	VOLATILE
4653905Smckusick #endif
4753905Smckusick 
4853905Smckusick int	tty00_is_console = 0;
4953905Smckusick 
5053905Smckusick #define	SCC_BUFSIZE	256
5153905Smckusick 
5253905Smckusick char	scc_buf[2][SCC_BUFSIZE];
5353905Smckusick 
scc_open(chan)5453905Smckusick scc_open(chan)
5553905Smckusick 	int chan;
5653905Smckusick {
5753905Smckusick 	register Scc_channel *scc = &sccsw[chan];
5853905Smckusick 	register int s;
5953905Smckusick 
6053905Smckusick 	s = splscc();
6153905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
6253905Smckusick 		scc_init(chan);
6353905Smckusick 		if (chan <= SCC_REMOTE1)
6453905Smckusick 			scc->r_dma.dma_addr = scc_buf[chan];
6553905Smckusick 		else
6653905Smckusick 			scc->r_dma.dma_addr =
6753905Smckusick 				malloc(SCC_BUFSIZE, M_DEVBUF, M_WAITOK);
6853905Smckusick 		scc->r_dma.dma_count = 0;
6953905Smckusick 		scc->scc_status |= CHAN_ACTIVE;
7053905Smckusick 	}
7153905Smckusick 	(void) splx(s);
7253905Smckusick 	return (0);
7353905Smckusick }
7453905Smckusick 
scc_probe(chan)7553905Smckusick scc_probe(chan)
7653905Smckusick 	register int chan;
7753905Smckusick {
7853905Smckusick 	VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
7953905Smckusick 	int s, temp, probe;
8053905Smckusick 
8153905Smckusick 	if (badaddr(port, 1))
8253905Smckusick 		return (0);
8353905Smckusick 	s = splscc();
8453905Smckusick 	temp = scc_read_reg(chan, RR12);
8553905Smckusick 	scc_write_reg(chan, WR12, PROBE_DATA);
8653905Smckusick 	probe = scc_read_reg(chan, RR12);
8753905Smckusick 	scc_write_reg(chan, WR12, temp);
8853905Smckusick 	(void) splx(s);
8953905Smckusick 	return (probe == PROBE_DATA);
9053905Smckusick }
9153905Smckusick 
scc_getc(chan)9253905Smckusick scc_getc(chan)
9353905Smckusick 	int chan;
9453905Smckusick {
9553905Smckusick 	VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
9653905Smckusick 	int c;
9753905Smckusick 
9853905Smckusick 	if (port->ctrl & R0_RxCA) {
9953905Smckusick 		SCCWAIT;
10053905Smckusick 		c = port->data;
10153905Smckusick 		SCCWAIT;
10253905Smckusick 		return (c);
10353905Smckusick 	}
10453905Smckusick 	SCCWAIT;
10553905Smckusick 	return (-1);
10653905Smckusick }
10753905Smckusick 
10853905Smckusick #ifndef notdef
scc_putc(chan,c)10953905Smckusick scc_putc(chan, c)
11053905Smckusick 	int chan, c;
11153905Smckusick {
11253905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
11353905Smckusick 
11453905Smckusick 	while ((port->ctrl & R0_TxBE) == 0)
11553905Smckusick 		SCCWAIT;
11653905Smckusick 	SCCWAIT;
11753905Smckusick 	port->data = c;
11853905Smckusick 	SCCWAIT;
11953905Smckusick }
12053905Smckusick #else
scc_putc(chan,c)12153905Smckusick scc_putc(chan, c)
12253905Smckusick         int chan, c;
12353905Smckusick {
12453905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
12553905Smckusick 	register VOLATILE u_char *ctrl = &sccsw[chan].scc_port->ctrl;
12653905Smckusick 	register VOLATILE u_char *data = &sccsw[chan].scc_port->data;
12753905Smckusick 
12853905Smckusick         SCCWAIT;
12953905Smckusick         while ((*ctrl & R0_TxBE) == 0) {
13053905Smckusick                 SCCWAIT;
13153905Smckusick         }
13253905Smckusick         SCCWAIT;
13353905Smckusick 
13453905Smckusick         *ctrl = W0_RES_TxINT;
13553905Smckusick         SCCWAIT;
13653905Smckusick         *data = (char)(c & 0xff);
13753905Smckusick         SCCWAIT;
13853905Smckusick         scc_write_reg(chan, WR1, W1_RxINT_ALL|W1_TxINTE|W1_EXTINTE|W1_PARITY);
13953905Smckusick         SCCWAIT;
14053905Smckusick }
14153905Smckusick #endif
14253905Smckusick 
scc_init(chan)14353905Smckusick scc_init(chan)
14453905Smckusick 	int chan;
14553905Smckusick {
14653905Smckusick 	register VOLATILE struct scc_reg *port;
14753905Smckusick 	register char *data;
14853905Smckusick 	register int i;
14953905Smckusick 	register Scc_channel *scc = &sccsw[chan];
15053905Smckusick 	int s;
15153905Smckusick 
15253905Smckusick 	s = splscc();
15353905Smckusick 	data = scc->scc_init;
15453905Smckusick 	port = scc->scc_port;
15553905Smckusick 	for (i = 0; i < N_INITDATA; i++) {
15653905Smckusick 		port->ctrl = *data++;
15753905Smckusick 		SCCWAIT;
15853905Smckusick 	}
15953905Smckusick 	scc_write_reg(chan, WR2, scc->scc_vec & ~0x0f);
16053905Smckusick /* KU:XXX
16153905Smckusick This must be bug because scc->scc_param is not initialized yet.
16253905Smckusick 	scc_set_param(chan, scc->scc_param);
16353905Smckusick */
16453905Smckusick 	(void) splx(s);
16553905Smckusick }
16653905Smckusick 
16753905Smckusick #define	vec_to_scc(vec)		((((vec) - SCCVEC0) >> 3) & 0x000f)
16853905Smckusick #define	vec_to_chan(vec)	scc2chan[vec_to_scc(vec)]
16953905Smckusick 
17053905Smckusick int scc2chan[] = {
17153905Smckusick 	1,	0,
17253905Smckusick 	3,	2,
17353905Smckusick 	5,	4,
17453905Smckusick 	7,	6,
17553905Smckusick 	9,	8
17653905Smckusick };
17753905Smckusick 
scc_rint(vec)17853905Smckusick scc_rint(vec)
17953905Smckusick 	int vec;
18053905Smckusick {
18153905Smckusick 	int chan = vec_to_chan(vec);
18253905Smckusick 	register Scc_channel *scc = &sccsw[chan];
18353905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
18453905Smckusick 	register int c;
18553905Smckusick 
18653905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
18753905Smckusick 		scc_reset(chan);
18853905Smckusick 		goto out;
18953905Smckusick 	}
19053905Smckusick 	if (scc->scc_status & LINE_BREAK){
19153905Smckusick 		scc->scc_status &= ~LINE_BREAK;
19253905Smckusick 		c = port->data;
19353905Smckusick 		SCCWAIT;
19453905Smckusick 	}
19553905Smckusick 	while (port->ctrl & R0_RxCA) {
19653905Smckusick 		SCCWAIT;
19753905Smckusick 		c = port->data;
19853905Smckusick 		SCCWAIT;
19953905Smckusick #if NRS > 0
20053905Smckusick 		scc_pdma(chan, c);
20153905Smckusick #endif
20253905Smckusick 	}
20353905Smckusick 	SCCWAIT;
20453905Smckusick out:
20553905Smckusick 	port->ctrl = W0_RES_IUS;
20653905Smckusick 	SCCWAIT;
20753905Smckusick }
20853905Smckusick 
20953905Smckusick #if NRS > 0
scc_enable(chan)21053905Smckusick scc_enable(chan)
21153905Smckusick 	int chan;
21253905Smckusick {
21353905Smckusick 	register Scc_channel *scc = &sccsw[chan];
21453905Smckusick 	int n;
21553905Smckusick 	int s;
21653905Smckusick 
21753905Smckusick 	s = splscc();
21853905Smckusick 	if ((n = scc->r_dma.dma_count) > 0) {
21953905Smckusick 		scc->r_dma.dma_count = 0;
22053905Smckusick 		rsrint(chan, scc->r_dma.dma_addr, n);
22153905Smckusick 	} else
22253905Smckusick 		scc->scc_status |= ENABLE;
22353905Smckusick 	(void) splx(s);
22453905Smckusick }
22553905Smckusick 
scc_pdma(chan,c)22653905Smckusick scc_pdma(chan, c)
22753905Smckusick 	int chan;
22853905Smckusick 	int c;
22953905Smckusick {
23053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
23153905Smckusick 	int n;
23253905Smckusick 
23353905Smckusick 	if (scc->r_dma.dma_count >= SCC_BUFSIZE)
23453905Smckusick 		printf("rs%d soft fifo overflow\n", chan);
23553905Smckusick 	else
23653905Smckusick 		scc->r_dma.dma_addr[scc->r_dma.dma_count++] = c;
23753905Smckusick 	if (scc->scc_status & ENABLE || scc->r_dma.dma_count >= SCC_BUFSIZE) {
23853905Smckusick 		scc->scc_status &= ~ENABLE;
23953905Smckusick 		n = scc->r_dma.dma_count;
24053905Smckusick 		scc->r_dma.dma_count = 0;
24153905Smckusick 		rsrint(chan, scc->r_dma.dma_addr, n);
24253905Smckusick 	}
24353905Smckusick }
24453905Smckusick #endif /* NRS > 0 */
24553905Smckusick 
scc_xint(vec)24653905Smckusick scc_xint(vec)
24753905Smckusick 	int vec;
24853905Smckusick {
24953905Smckusick 	int chan = vec_to_chan(vec);
25053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
25153905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
25253905Smckusick 
25353905Smckusick 	if (scc->scc_status & OSTOP)
25453905Smckusick 		scc->scc_status &= ~(OACTIVE|OSTOP);
25553905Smckusick 	if (scc->scc_status & OFLUSH) {
25653905Smckusick 		scc->x_dma.dma_count = 0;
25753905Smckusick 		scc->scc_status &= ~(OACTIVE|OFLUSH);
25853905Smckusick 	}
25953905Smckusick 	if ((scc->scc_status & OACTIVE) && (scc->x_dma.dma_count > 0)) {
26053905Smckusick 		port->data = *(scc->x_dma.dma_addr)++;
26153905Smckusick 		SCCWAIT;
26253905Smckusick 		scc->x_dma.dma_count--;
26353905Smckusick 	} else {
26453905Smckusick 		port->ctrl = W0_RES_TxINT;
26553905Smckusick 		SCCWAIT;
26653905Smckusick 		scc->scc_status &= ~OACTIVE;
26753905Smckusick #if NRS > 0
26853905Smckusick 		if (scc->x_dma.dma_count == 0)
26953905Smckusick 			rsxint(chan);
27053905Smckusick #endif
27153905Smckusick 	}
27253905Smckusick 	port->ctrl = W0_RES_IUS;
27353905Smckusick 	SCCWAIT;
27453905Smckusick }
27553905Smckusick 
scc_sint(vec)27653905Smckusick scc_sint(vec)
27753905Smckusick 	int vec;
27853905Smckusick {
27953905Smckusick 	int chan = vec_to_chan(vec);
28053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
28153905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
28253905Smckusick 	register int status;
28353905Smckusick 	register int param = 0;
28453905Smckusick 
28553905Smckusick 	port->ctrl = W0_RES_EXT;
28653905Smckusick 	SCCWAIT;
28753905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
28853905Smckusick 		scc_reset(chan);
28953905Smckusick 		goto out;
29053905Smckusick 	}
29153905Smckusick 	status = port->ctrl;
29253905Smckusick 	SCCWAIT;
29353905Smckusick 	if (status & R0_DCD)
29453905Smckusick 		param |= DCD;
29553905Smckusick 	if (status & R0_CTS)
29653905Smckusick 		param |= CTS;
29753905Smckusick 	if (status & R0_BREAK){
29853905Smckusick 		param |= RBREAK;
29953905Smckusick 		scc->scc_status |= LINE_BREAK;
30053905Smckusick 	}
30153905Smckusick 	if ((scc->scc_param & (DCD|CTS|RBREAK)) != param) {
30253905Smckusick 		scc->scc_param = (scc->scc_param & ~(DCD|CTS|RBREAK)) | param;
30353905Smckusick #if NRS > 0
30453905Smckusick 		rssint(chan, scc->scc_param);
30553905Smckusick #endif
30653905Smckusick 	}
30753905Smckusick out:
30853905Smckusick 	port->ctrl = W0_RES_IUS;
30953905Smckusick 	SCCWAIT;
31053905Smckusick }
31153905Smckusick 
scc_cint(vec)31253905Smckusick scc_cint(vec)
31353905Smckusick 	int vec;
31453905Smckusick {
31553905Smckusick 	int chan = vec_to_chan(vec);
31653905Smckusick 	register Scc_channel *scc = &sccsw[chan];
31753905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
31853905Smckusick 	register int status;
31953905Smckusick 	int c;
32053905Smckusick 
32153905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
32253905Smckusick 		scc_reset(chan);
32353905Smckusick 		goto out;
32453905Smckusick 	}
32553905Smckusick 	status = scc_read_reg(chan, RR1);
32653905Smckusick 	if (status & R1_CRC)
32753905Smckusick 		scc->scc_param |= FRAMING_ERROR;
32853905Smckusick 	if (status & R1_OVRUN) {
32953905Smckusick 		if ((scc->scc_param & OVERRUN_ERROR) == 0) {
33053905Smckusick 			scc->scc_param |= OVERRUN_ERROR;
33153905Smckusick #if NRS > 0
33253905Smckusick 			rssint(chan, scc->scc_param);
33357610Sutashiro #endif
33453905Smckusick 		}
33553905Smckusick 	}
33653905Smckusick 	if (status & R1_PARITY) {
33753905Smckusick 		scc->scc_param |= SCC_PARITY_ERROR;
33853905Smckusick 		while (port->ctrl & R0_RxCA) {
33953905Smckusick 			SCCWAIT;
34053905Smckusick 			c = port->data;
34153905Smckusick 			SCCWAIT;
34253905Smckusick #if NRS > 0
34353905Smckusick 			if (scc->scc_param & NOCHECK)
34453905Smckusick 				scc_pdma(chan, c);
34553905Smckusick #endif
34653905Smckusick 		}
34753905Smckusick 		SCCWAIT;
34853905Smckusick 	}
34953905Smckusick out:
35053905Smckusick 	port->ctrl = W0_RES_ERROR;
35153905Smckusick 	SCCWAIT;
35253905Smckusick 	port->ctrl = W0_RES_IUS;
35353905Smckusick 	SCCWAIT;
35453905Smckusick }
35553905Smckusick 
scc_write_reg(chan,reg,data)35653905Smckusick scc_write_reg(chan, reg, data)
35753905Smckusick 	int chan, reg, data;
35853905Smckusick {
35953905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
36053905Smckusick 
36153905Smckusick 	port->ctrl = reg;
36253905Smckusick 	SCCWAIT;
36353905Smckusick 	port->ctrl = data;
36453905Smckusick 	SCCWAIT;
36553905Smckusick }
36653905Smckusick 
scc_read_reg(chan,reg)36753905Smckusick scc_read_reg(chan, reg)
36853905Smckusick 	int chan, reg;
36953905Smckusick {
37053905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
37153905Smckusick 	int result;
37253905Smckusick 
37353905Smckusick 	port->ctrl = reg;
37453905Smckusick 	SCCWAIT;
37553905Smckusick 	result = port->ctrl;
37653905Smckusick 	SCCWAIT;
37753905Smckusick 	return (result);
37853905Smckusick }
37953905Smckusick 
38053905Smckusick #ifdef news3400
38153905Smckusick #define	DSRA	0x01
38253905Smckusick #define	RIA	0x02
38353905Smckusick #define	DSRB	0x04
38453905Smckusick #define	RIB	0x08
38553905Smckusick 
38653905Smckusick #define	DSRC	0x01
38753905Smckusick #define	RIC	0x02
38853905Smckusick #define	DSRD	0x04
38953905Smckusick #define	RID	0x08
39053905Smckusick #define	DSRE	0x10
39153905Smckusick #define	RIE	0x20
39253905Smckusick #define	DSRF	0x40
39353905Smckusick #define	RIF	0x80
39453905Smckusick #endif /* news3400 */
39553905Smckusick 
39653905Smckusick struct ri_dsr {
39753905Smckusick 	char	*status;
39853905Smckusick 	int	ri;
39953905Smckusick 	int	dsr;
40053905Smckusick } ri_dsr[] = {
40153905Smckusick 	{ (char *)SCC_STATUS0, RIA, DSRA },
40253905Smckusick 	{ (char *)SCC_STATUS0, RIB, DSRB },
40357610Sutashiro #if !defined(news3200)
40453905Smckusick 	{ (char *)SCC_STATUS1, RIC, DSRC },
40553905Smckusick 	{ (char *)SCC_STATUS1, RID, DSRD },
40653905Smckusick 	{ (char *)SCC_STATUS1, RIE, DSRE },
40753905Smckusick 	{ (char *)SCC_STATUS1, RIF, DSRF },
40853905Smckusick 	{ (char *)SCC_STATUS2, RIC, DSRC },
40953905Smckusick 	{ (char *)SCC_STATUS2, RID, DSRD },
41053905Smckusick 	{ (char *)SCC_STATUS2, RIE, DSRE },
41153905Smckusick 	{ (char *)SCC_STATUS2, RIF, DSRF }
41257610Sutashiro #endif /* !news3200 */
41353905Smckusick };
41453905Smckusick 
get_ri_dsr(chan)41553905Smckusick get_ri_dsr(chan)
41653905Smckusick 	int chan;
41753905Smckusick {
41853905Smckusick 	register struct ri_dsr *p;
41953905Smckusick 	register int status, param;
42053905Smckusick 
42153905Smckusick 	param = 0;
42253905Smckusick 	p = &ri_dsr[chan];
42353905Smckusick 	status = *p->status;
42453905Smckusick 	if ((status & p->ri) == 0)
42553905Smckusick 		param |= RI;
42653905Smckusick 	if ((status & p->dsr) == 0)
42753905Smckusick 		param |= DSR;
42853905Smckusick 	return (param);
42953905Smckusick }
43053905Smckusick 
43157610Sutashiro #if defined(news3400)
43253905Smckusick /*
43353905Smckusick  *	tc0 = floor(4915200 / 32 / baudrate - 2 + 0.5);
43453905Smckusick  */
43553905Smckusick static int tc0[] = {
43653905Smckusick 	0,		/* B0 */
43753905Smckusick 	3070,		/* B50 */
43853905Smckusick 	2046,		/* B75 */
43953905Smckusick 	1394,		/* B110 */
44053905Smckusick 	1144,		/* B134 */
44153905Smckusick 	1022,		/* B150 */
44253905Smckusick 	766,		/* B200 */
44353905Smckusick 	510,		/* B300 */
44453905Smckusick 	254,		/* B600 */
44553905Smckusick 	126,		/* B1200 */
44653905Smckusick 	83,		/* B1800 */
44753905Smckusick 	62,		/* B2400 */
44853905Smckusick 	30,		/* B4800 */
44953905Smckusick 	14,		/* B9600 */
45053905Smckusick 	6,		/* EXTA (B19200) */
45153905Smckusick 	2		/* EXTB (B38400) */
45253905Smckusick 	};
45357610Sutashiro #endif /* news3400 */
45453905Smckusick 
45553905Smckusick static int tc1[] = {
45653905Smckusick /*
45753905Smckusick  *	tc1 = floor(3686400 / 32 / baudrate - 2 + 0.5);
45853905Smckusick  */
45953905Smckusick 	0,		/* B0 */
46053905Smckusick 	2302,		/* B50 */
46153905Smckusick 	1534,		/* B75 */
46253905Smckusick 	1045,		/* B110 */
46353905Smckusick 	858,		/* B134 */
46453905Smckusick 	766,		/* B150 */
46553905Smckusick 	574,		/* B200 */
46653905Smckusick 	382,		/* B300 */
46753905Smckusick 	190,		/* B600 */
46853905Smckusick 	94,		/* B1200 */
46953905Smckusick 	62,		/* B1800 */
47053905Smckusick 	46,		/* B2400 */
47153905Smckusick 	22,		/* B4800 */
47253905Smckusick 	10,		/* B9600 */
47353905Smckusick 	4,		/* B19200 */
47453905Smckusick 	1,		/* B38400 */
47553905Smckusick };
47653905Smckusick 
scc_set_param(chan,param)47753905Smckusick scc_set_param(chan, param)
47853905Smckusick 	int chan;
47953905Smckusick 	register int param;
48053905Smckusick {
48153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
48253905Smckusick 	register int bit, baud, *tc;
48353905Smckusick 	int s;
48453905Smckusick 
48553905Smckusick 	s = splscc();
48653905Smckusick 
48753905Smckusick 	/*
48853905Smckusick 	 * Baud rate / external clock
48953905Smckusick 	 */
49053905Smckusick 	if ((baud = param & BAUD_RATE) == EXTB && chan <= SCC_REMOTE1 &&
49153905Smckusick 	    param & EXTCLK_ENABLE) {
49253905Smckusick 		scc_write_reg(chan, WR11, W11_RxC_RTxC|W11_TxC_TRxC);
49353905Smckusick 		bit = W4_X1;
49453905Smckusick 	} else {
49553905Smckusick 		tc = (chan <= SCC_REMOTE1) ? tc0 : tc1;
49653905Smckusick 		scc_write_reg(chan, WR11, W11_RxC_BRG|W11_TxC_BRG);
49753905Smckusick 		scc_write_reg(chan, WR12, tc[baud] & 0xff);
49853905Smckusick 		scc_write_reg(chan, WR13, tc[baud] >> 8);
49953905Smckusick 		bit = W4_X16;
50053905Smckusick 	}
50153905Smckusick 
50253905Smckusick 	/*
50353905Smckusick 	 * Clock mode / parity / stop bit
50453905Smckusick 	 */
50553905Smckusick 	if (param & PARITY) {
50653905Smckusick 		bit |= W4_PARITY;
50753905Smckusick 		if (param & EVEN)
50853905Smckusick 			bit |= W4_EVEN;
50953905Smckusick 	}
51053905Smckusick 	switch (param & STOPBIT) {
51153905Smckusick 
51253905Smckusick 	case STOP1:
51353905Smckusick 		bit |= W4_STOP1;
51453905Smckusick 		break;
51553905Smckusick 
51653905Smckusick 	case STOP1_5:
51753905Smckusick 		bit |= W4_STOP1_5;
51853905Smckusick 		break;
51953905Smckusick 
52053905Smckusick 	case STOP2:
52153905Smckusick 		bit |= W4_STOP2;
52253905Smckusick 		break;
52353905Smckusick 
52453905Smckusick 	}
52553905Smckusick 	scc_write_reg(chan, WR4, bit);
52653905Smckusick 
52753905Smckusick 	/*
52853905Smckusick 	 * Receiver enable / receive character size / auto enable
52953905Smckusick 	 */
53053905Smckusick 	bit = (param & RXE ? W3_RxE : 0);
53153905Smckusick 	switch (param & CHAR_SIZE) {
53253905Smckusick 
53353905Smckusick 	case C5BIT:
53453905Smckusick 		break;
53553905Smckusick 
53653905Smckusick 	case C6BIT:
53753905Smckusick 		bit |= W3_Rx6BIT;
53853905Smckusick 		break;
53953905Smckusick 
54053905Smckusick 	case C7BIT:
54153905Smckusick 		bit |= W3_Rx7BIT;
54253905Smckusick 		break;
54353905Smckusick 
54453905Smckusick 	case C8BIT:
54553905Smckusick 		bit |= W3_Rx8BIT;
54653905Smckusick 		break;
54753905Smckusick 	}
54853905Smckusick #ifdef AUTO_ENABLE
54953905Smckusick 	if (param & AUTO_ENABLE)
55053905Smckusick 		bit |= W3_AUTO;
55153905Smckusick #endif /* AUTO_ENABLE */
55253905Smckusick 	scc_write_reg(chan, WR3, bit);
55353905Smckusick 
55453905Smckusick 	/*
55553905Smckusick 	 * Transmitter enable / transmit character size / RTS / DTR / BREAK
55653905Smckusick 	 */
55753905Smckusick 	bit = (param & TXE ? W5_TxE : 0);
55853905Smckusick 	switch (param & CHAR_SIZE) {
55953905Smckusick 
56053905Smckusick 	case C5BIT:
56153905Smckusick 		break;
56253905Smckusick 
56353905Smckusick 	case C6BIT:
56453905Smckusick 		bit |= W5_Tx6BIT;
56553905Smckusick 		break;
56653905Smckusick 
56753905Smckusick 	case C7BIT:
56853905Smckusick 		bit |= W5_Tx7BIT;
56953905Smckusick 		break;
57053905Smckusick 
57153905Smckusick 	case C8BIT:
57253905Smckusick 		bit |= W5_Tx8BIT;
57353905Smckusick 		break;
57453905Smckusick 	}
57553905Smckusick 	if (param & RTS)
57653905Smckusick 		bit |= W5_RTS;
57753905Smckusick 	if (param & DTR)
57853905Smckusick 		bit |= W5_DTR;
57953905Smckusick 	if (param & XBREAK)
58053905Smckusick 		bit |= W5_BREAK;
58153905Smckusick 	scc_write_reg(chan, WR5, bit);
58253905Smckusick 	scc->scc_param = param;
58353905Smckusick 	(void) splx(s);
58453905Smckusick 	return (0);
58553905Smckusick }
58653905Smckusick 
scc_get_param(chan)58753905Smckusick scc_get_param(chan)
58853905Smckusick 	int chan;
58953905Smckusick {
59053905Smckusick 	register Scc_channel *scc = &sccsw[chan];
59153905Smckusick 
59253905Smckusick 	scc->scc_param = (scc->scc_param & ~(RI|DSR)) | get_ri_dsr(chan);
59353905Smckusick 	return (scc->scc_param);
59453905Smckusick }
59553905Smckusick 
scc_get_status(chan)59653905Smckusick scc_get_status(chan)
59753905Smckusick 	int chan;
59853905Smckusick {
59953905Smckusick 
60053905Smckusick 	return (sccsw[chan].scc_status);
60153905Smckusick }
60253905Smckusick 
scc_set_status(chan,stat)60353905Smckusick scc_set_status(chan, stat)
60453905Smckusick 	int chan, stat;
60553905Smckusick {
60653905Smckusick 
60753905Smckusick 	sccsw[chan].scc_status = stat;
60853905Smckusick 
60953905Smckusick 	return (0);
61053905Smckusick }
61153905Smckusick 
scc_flush(chan)61253905Smckusick scc_flush(chan)
61353905Smckusick 	int chan;
61453905Smckusick {
61553905Smckusick 	register Scc_channel *scc = &sccsw[chan];
61653905Smckusick 
61753905Smckusick 	if (scc->scc_status & OACTIVE)
61853905Smckusick 		scc->scc_status |= OFLUSH;
61953905Smckusick 	else if (scc->x_dma.dma_count > 0) {
62053905Smckusick 		scc->x_dma.dma_count = 0;
62153905Smckusick #if NRS > 0
62253905Smckusick 		rsxint(chan);
62353905Smckusick #endif
62453905Smckusick 	}
62553905Smckusick 	return (0);
62653905Smckusick }
62753905Smckusick 
scc_start(chan)62853905Smckusick scc_start(chan)
62953905Smckusick 	int chan;
63053905Smckusick {
63153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
63253905Smckusick 
63353905Smckusick 	if ((scc->scc_status & OACTIVE) == 0 && scc->x_dma.dma_count > 0) {
63453905Smckusick 		scc->scc_port->data = *(scc->x_dma.dma_addr)++;
63553905Smckusick 		SCCWAIT;
63653905Smckusick 		scc->x_dma.dma_count--;
63753905Smckusick 		scc->scc_status |= OACTIVE;
63853905Smckusick 	}
63953905Smckusick 	return (0);
64053905Smckusick }
64153905Smckusick 
scc_stop(chan)64253905Smckusick scc_stop(chan)
64353905Smckusick 	int chan;
64453905Smckusick {
64553905Smckusick 	register Scc_channel *scc = &sccsw[chan];
64653905Smckusick 
64753905Smckusick 	if (scc->scc_status & OACTIVE)
64853905Smckusick 		scc->scc_status |= OSTOP;
64953905Smckusick 	return (0);
65053905Smckusick }
65153905Smckusick 
scc_write(chan,buf,count)65253905Smckusick scc_write(chan, buf, count)
65353905Smckusick 	int chan;
65453905Smckusick 	caddr_t buf;
65553905Smckusick 	int count;
65653905Smckusick {
65753905Smckusick 	register Scc_channel *scc = &sccsw[chan];
65853905Smckusick 
65953905Smckusick 	if (count <= 0)
66053905Smckusick 		return (0);
66153905Smckusick 	scc->x_dma.dma_addr = buf;
66253905Smckusick 	scc->x_dma.dma_count = count;
66353905Smckusick 	scc_start(chan);
66453905Smckusick 	return (count);
66553905Smckusick }
66653905Smckusick 
scc_error_write(chan,buf,count)66753905Smckusick scc_error_write(chan, buf, count)
66853905Smckusick 	int chan;
66953905Smckusick 	register char *buf;
67053905Smckusick 	register int count;
67153905Smckusick {
67253905Smckusick 	register int i;
67353905Smckusick 
67453905Smckusick 	for (i = 0; i < count; i++)
67553905Smckusick 		scc_putc(chan, *buf++);
67653905Smckusick 	return (i);
67753905Smckusick }
67853905Smckusick 
scc_reset(chan)67953905Smckusick scc_reset(chan)
68053905Smckusick 	int chan;
68153905Smckusick {
68253905Smckusick 	register Scc_channel *scc = &sccsw[chan];
68353905Smckusick 
68453905Smckusick 	while (scc_getc(chan) != -1)
68553905Smckusick 		;
68653905Smckusick 	scc->scc_status &= ~CHAN_ACTIVE;
68753905Smckusick }
688