xref: /csrg-svn/sys/news3400/sio/scc.c (revision 57610)
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*57610Sutashiro  *	@(#)scc.c	7.3 (Berkeley) 01/20/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/fix_machine_type.h>
2757184Sutashiro #include <machine/adrsmap.h>
2853905Smckusick 
2953905Smckusick #include "rs.h"
3053905Smckusick 
3157184Sutashiro #include <sys/param.h>
3257184Sutashiro #include <sys/ioctl.h>
3357184Sutashiro #include <sys/tty.h>
3457184Sutashiro #include <sys/malloc.h>
3553905Smckusick 
3657184Sutashiro #include <news3400/sio/sccparam.h>
3757184Sutashiro #include <news3400/sio/sccreg.h>
3857184Sutashiro #include <news3400/sio/scc.h>
3957184Sutashiro #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 	1,	0,
17353905Smckusick 	3,	2,
17453905Smckusick 	5,	4,
17553905Smckusick 	7,	6,
17653905Smckusick 	9,	8
17753905Smckusick };
17853905Smckusick 
17953905Smckusick scc_rint(vec)
18053905Smckusick 	int vec;
18153905Smckusick {
18253905Smckusick 	int chan = vec_to_chan(vec);
18353905Smckusick 	register Scc_channel *scc = &sccsw[chan];
18453905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
18553905Smckusick 	register int c;
18653905Smckusick 
18753905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
18853905Smckusick 		scc_reset(chan);
18953905Smckusick 		goto out;
19053905Smckusick 	}
19153905Smckusick 	if (scc->scc_status & LINE_BREAK){
19253905Smckusick 		scc->scc_status &= ~LINE_BREAK;
19353905Smckusick 		c = port->data;
19453905Smckusick 		SCCWAIT;
19553905Smckusick 	}
19653905Smckusick 	while (port->ctrl & R0_RxCA) {
19753905Smckusick 		SCCWAIT;
19853905Smckusick 		c = port->data;
19953905Smckusick 		SCCWAIT;
20053905Smckusick #if NRS > 0
20153905Smckusick 		scc_pdma(chan, c);
20253905Smckusick #endif
20353905Smckusick 	}
20453905Smckusick 	SCCWAIT;
20553905Smckusick out:
20653905Smckusick 	port->ctrl = W0_RES_IUS;
20753905Smckusick 	SCCWAIT;
20853905Smckusick }
20953905Smckusick 
21053905Smckusick #if NRS > 0
21153905Smckusick scc_enable(chan)
21253905Smckusick 	int chan;
21353905Smckusick {
21453905Smckusick 	register Scc_channel *scc = &sccsw[chan];
21553905Smckusick 	int n;
21653905Smckusick 	int s;
21753905Smckusick 
21853905Smckusick 	s = splscc();
21953905Smckusick 	if ((n = scc->r_dma.dma_count) > 0) {
22053905Smckusick 		scc->r_dma.dma_count = 0;
22153905Smckusick 		rsrint(chan, scc->r_dma.dma_addr, n);
22253905Smckusick 	} else
22353905Smckusick 		scc->scc_status |= ENABLE;
22453905Smckusick 	(void) splx(s);
22553905Smckusick }
22653905Smckusick 
22753905Smckusick scc_pdma(chan, c)
22853905Smckusick 	int chan;
22953905Smckusick 	int c;
23053905Smckusick {
23153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
23253905Smckusick 	int n;
23353905Smckusick 
23453905Smckusick 	if (scc->r_dma.dma_count >= SCC_BUFSIZE)
23553905Smckusick 		printf("rs%d soft fifo overflow\n", chan);
23653905Smckusick 	else
23753905Smckusick 		scc->r_dma.dma_addr[scc->r_dma.dma_count++] = c;
23853905Smckusick 	if (scc->scc_status & ENABLE || scc->r_dma.dma_count >= SCC_BUFSIZE) {
23953905Smckusick 		scc->scc_status &= ~ENABLE;
24053905Smckusick 		n = scc->r_dma.dma_count;
24153905Smckusick 		scc->r_dma.dma_count = 0;
24253905Smckusick 		rsrint(chan, scc->r_dma.dma_addr, n);
24353905Smckusick 	}
24453905Smckusick }
24553905Smckusick #endif /* NRS > 0 */
24653905Smckusick 
24753905Smckusick scc_xint(vec)
24853905Smckusick 	int vec;
24953905Smckusick {
25053905Smckusick 	int chan = vec_to_chan(vec);
25153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
25253905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
25353905Smckusick 
25453905Smckusick 	if (scc->scc_status & OSTOP)
25553905Smckusick 		scc->scc_status &= ~(OACTIVE|OSTOP);
25653905Smckusick 	if (scc->scc_status & OFLUSH) {
25753905Smckusick 		scc->x_dma.dma_count = 0;
25853905Smckusick 		scc->scc_status &= ~(OACTIVE|OFLUSH);
25953905Smckusick 	}
26053905Smckusick 	if ((scc->scc_status & OACTIVE) && (scc->x_dma.dma_count > 0)) {
26153905Smckusick 		port->data = *(scc->x_dma.dma_addr)++;
26253905Smckusick 		SCCWAIT;
26353905Smckusick 		scc->x_dma.dma_count--;
26453905Smckusick 	} else {
26553905Smckusick 		port->ctrl = W0_RES_TxINT;
26653905Smckusick 		SCCWAIT;
26753905Smckusick 		scc->scc_status &= ~OACTIVE;
26853905Smckusick #if NRS > 0
26953905Smckusick 		if (scc->x_dma.dma_count == 0)
27053905Smckusick 			rsxint(chan);
27153905Smckusick #endif
27253905Smckusick 	}
27353905Smckusick 	port->ctrl = W0_RES_IUS;
27453905Smckusick 	SCCWAIT;
27553905Smckusick }
27653905Smckusick 
27753905Smckusick scc_sint(vec)
27853905Smckusick 	int vec;
27953905Smckusick {
28053905Smckusick 	int chan = vec_to_chan(vec);
28153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
28253905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
28353905Smckusick 	register int status;
28453905Smckusick 	register int param = 0;
28553905Smckusick 
28653905Smckusick 	port->ctrl = W0_RES_EXT;
28753905Smckusick 	SCCWAIT;
28853905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
28953905Smckusick 		scc_reset(chan);
29053905Smckusick 		goto out;
29153905Smckusick 	}
29253905Smckusick 	status = port->ctrl;
29353905Smckusick 	SCCWAIT;
29453905Smckusick 	if (status & R0_DCD)
29553905Smckusick 		param |= DCD;
29653905Smckusick 	if (status & R0_CTS)
29753905Smckusick 		param |= CTS;
29853905Smckusick 	if (status & R0_BREAK){
29953905Smckusick 		param |= RBREAK;
30053905Smckusick 		scc->scc_status |= LINE_BREAK;
30153905Smckusick 	}
30253905Smckusick 	if ((scc->scc_param & (DCD|CTS|RBREAK)) != param) {
30353905Smckusick 		scc->scc_param = (scc->scc_param & ~(DCD|CTS|RBREAK)) | param;
30453905Smckusick #if NRS > 0
30553905Smckusick 		rssint(chan, scc->scc_param);
30653905Smckusick #endif
30753905Smckusick 	}
30853905Smckusick out:
30953905Smckusick 	port->ctrl = W0_RES_IUS;
31053905Smckusick 	SCCWAIT;
31153905Smckusick }
31253905Smckusick 
31353905Smckusick scc_cint(vec)
31453905Smckusick 	int vec;
31553905Smckusick {
31653905Smckusick 	int chan = vec_to_chan(vec);
31753905Smckusick 	register Scc_channel *scc = &sccsw[chan];
31853905Smckusick 	register VOLATILE struct scc_reg *port = scc->scc_port;
31953905Smckusick 	register int status;
32053905Smckusick 	int c;
32153905Smckusick 
32253905Smckusick 	if ((scc->scc_status & CHAN_ACTIVE) == 0) {
32353905Smckusick 		scc_reset(chan);
32453905Smckusick 		goto out;
32553905Smckusick 	}
32653905Smckusick 	status = scc_read_reg(chan, RR1);
32753905Smckusick 	if (status & R1_CRC)
32853905Smckusick 		scc->scc_param |= FRAMING_ERROR;
32953905Smckusick 	if (status & R1_OVRUN) {
33053905Smckusick 		if ((scc->scc_param & OVERRUN_ERROR) == 0) {
33153905Smckusick 			scc->scc_param |= OVERRUN_ERROR;
33253905Smckusick #if NRS > 0
33353905Smckusick 			rssint(chan, scc->scc_param);
334*57610Sutashiro #endif
33553905Smckusick 		}
33653905Smckusick 	}
33753905Smckusick 	if (status & R1_PARITY) {
33853905Smckusick 		scc->scc_param |= SCC_PARITY_ERROR;
33953905Smckusick 		while (port->ctrl & R0_RxCA) {
34053905Smckusick 			SCCWAIT;
34153905Smckusick 			c = port->data;
34253905Smckusick 			SCCWAIT;
34353905Smckusick #if NRS > 0
34453905Smckusick 			if (scc->scc_param & NOCHECK)
34553905Smckusick 				scc_pdma(chan, c);
34653905Smckusick #endif
34753905Smckusick 		}
34853905Smckusick 		SCCWAIT;
34953905Smckusick 	}
35053905Smckusick out:
35153905Smckusick 	port->ctrl = W0_RES_ERROR;
35253905Smckusick 	SCCWAIT;
35353905Smckusick 	port->ctrl = W0_RES_IUS;
35453905Smckusick 	SCCWAIT;
35553905Smckusick }
35653905Smckusick 
35753905Smckusick scc_write_reg(chan, reg, data)
35853905Smckusick 	int chan, reg, data;
35953905Smckusick {
36053905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
36153905Smckusick 
36253905Smckusick 	port->ctrl = reg;
36353905Smckusick 	SCCWAIT;
36453905Smckusick 	port->ctrl = data;
36553905Smckusick 	SCCWAIT;
36653905Smckusick }
36753905Smckusick 
36853905Smckusick scc_read_reg(chan, reg)
36953905Smckusick 	int chan, reg;
37053905Smckusick {
37153905Smckusick 	register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
37253905Smckusick 	int result;
37353905Smckusick 
37453905Smckusick 	port->ctrl = reg;
37553905Smckusick 	SCCWAIT;
37653905Smckusick 	result = port->ctrl;
37753905Smckusick 	SCCWAIT;
37853905Smckusick 	return (result);
37953905Smckusick }
38053905Smckusick 
38153905Smckusick #ifdef news3400
38253905Smckusick #define	DSRA	0x01
38353905Smckusick #define	RIA	0x02
38453905Smckusick #define	DSRB	0x04
38553905Smckusick #define	RIB	0x08
38653905Smckusick 
38753905Smckusick #define	DSRC	0x01
38853905Smckusick #define	RIC	0x02
38953905Smckusick #define	DSRD	0x04
39053905Smckusick #define	RID	0x08
39153905Smckusick #define	DSRE	0x10
39253905Smckusick #define	RIE	0x20
39353905Smckusick #define	DSRF	0x40
39453905Smckusick #define	RIF	0x80
39553905Smckusick #endif /* news3400 */
39653905Smckusick 
39753905Smckusick struct ri_dsr {
39853905Smckusick 	char	*status;
39953905Smckusick 	int	ri;
40053905Smckusick 	int	dsr;
40153905Smckusick } ri_dsr[] = {
40253905Smckusick 	{ (char *)SCC_STATUS0, RIA, DSRA },
40353905Smckusick 	{ (char *)SCC_STATUS0, RIB, DSRB },
404*57610Sutashiro #if !defined(news3200)
40553905Smckusick 	{ (char *)SCC_STATUS1, RIC, DSRC },
40653905Smckusick 	{ (char *)SCC_STATUS1, RID, DSRD },
40753905Smckusick 	{ (char *)SCC_STATUS1, RIE, DSRE },
40853905Smckusick 	{ (char *)SCC_STATUS1, RIF, DSRF },
40953905Smckusick 	{ (char *)SCC_STATUS2, RIC, DSRC },
41053905Smckusick 	{ (char *)SCC_STATUS2, RID, DSRD },
41153905Smckusick 	{ (char *)SCC_STATUS2, RIE, DSRE },
41253905Smckusick 	{ (char *)SCC_STATUS2, RIF, DSRF }
413*57610Sutashiro #endif /* !news3200 */
41453905Smckusick };
41553905Smckusick 
41653905Smckusick get_ri_dsr(chan)
41753905Smckusick 	int chan;
41853905Smckusick {
41953905Smckusick 	register struct ri_dsr *p;
42053905Smckusick 	register int status, param;
42153905Smckusick 
42253905Smckusick 	param = 0;
42353905Smckusick 	p = &ri_dsr[chan];
42453905Smckusick 	status = *p->status;
42553905Smckusick 	if ((status & p->ri) == 0)
42653905Smckusick 		param |= RI;
42753905Smckusick 	if ((status & p->dsr) == 0)
42853905Smckusick 		param |= DSR;
42953905Smckusick 	return (param);
43053905Smckusick }
43153905Smckusick 
432*57610Sutashiro #if defined(news3400)
43353905Smckusick /*
43453905Smckusick  *	tc0 = floor(4915200 / 32 / baudrate - 2 + 0.5);
43553905Smckusick  */
43653905Smckusick static int tc0[] = {
43753905Smckusick 	0,		/* B0 */
43853905Smckusick 	3070,		/* B50 */
43953905Smckusick 	2046,		/* B75 */
44053905Smckusick 	1394,		/* B110 */
44153905Smckusick 	1144,		/* B134 */
44253905Smckusick 	1022,		/* B150 */
44353905Smckusick 	766,		/* B200 */
44453905Smckusick 	510,		/* B300 */
44553905Smckusick 	254,		/* B600 */
44653905Smckusick 	126,		/* B1200 */
44753905Smckusick 	83,		/* B1800 */
44853905Smckusick 	62,		/* B2400 */
44953905Smckusick 	30,		/* B4800 */
45053905Smckusick 	14,		/* B9600 */
45153905Smckusick 	6,		/* EXTA (B19200) */
45253905Smckusick 	2		/* EXTB (B38400) */
45353905Smckusick 	};
454*57610Sutashiro #endif /* news3400 */
45553905Smckusick 
45653905Smckusick static int tc1[] = {
45753905Smckusick /*
45853905Smckusick  *	tc1 = floor(3686400 / 32 / baudrate - 2 + 0.5);
45953905Smckusick  */
46053905Smckusick 	0,		/* B0 */
46153905Smckusick 	2302,		/* B50 */
46253905Smckusick 	1534,		/* B75 */
46353905Smckusick 	1045,		/* B110 */
46453905Smckusick 	858,		/* B134 */
46553905Smckusick 	766,		/* B150 */
46653905Smckusick 	574,		/* B200 */
46753905Smckusick 	382,		/* B300 */
46853905Smckusick 	190,		/* B600 */
46953905Smckusick 	94,		/* B1200 */
47053905Smckusick 	62,		/* B1800 */
47153905Smckusick 	46,		/* B2400 */
47253905Smckusick 	22,		/* B4800 */
47353905Smckusick 	10,		/* B9600 */
47453905Smckusick 	4,		/* B19200 */
47553905Smckusick 	1,		/* B38400 */
47653905Smckusick };
47753905Smckusick 
47853905Smckusick scc_set_param(chan, param)
47953905Smckusick 	int chan;
48053905Smckusick 	register int param;
48153905Smckusick {
48253905Smckusick 	register Scc_channel *scc = &sccsw[chan];
48353905Smckusick 	register int bit, baud, *tc;
48453905Smckusick 	int s;
48553905Smckusick 
48653905Smckusick 	s = splscc();
48753905Smckusick 
48853905Smckusick 	/*
48953905Smckusick 	 * Baud rate / external clock
49053905Smckusick 	 */
49153905Smckusick 	if ((baud = param & BAUD_RATE) == EXTB && chan <= SCC_REMOTE1 &&
49253905Smckusick 	    param & EXTCLK_ENABLE) {
49353905Smckusick 		scc_write_reg(chan, WR11, W11_RxC_RTxC|W11_TxC_TRxC);
49453905Smckusick 		bit = W4_X1;
49553905Smckusick 	} else {
49653905Smckusick 		tc = (chan <= SCC_REMOTE1) ? tc0 : tc1;
49753905Smckusick 		scc_write_reg(chan, WR11, W11_RxC_BRG|W11_TxC_BRG);
49853905Smckusick 		scc_write_reg(chan, WR12, tc[baud] & 0xff);
49953905Smckusick 		scc_write_reg(chan, WR13, tc[baud] >> 8);
50053905Smckusick 		bit = W4_X16;
50153905Smckusick 	}
50253905Smckusick 
50353905Smckusick 	/*
50453905Smckusick 	 * Clock mode / parity / stop bit
50553905Smckusick 	 */
50653905Smckusick 	if (param & PARITY) {
50753905Smckusick 		bit |= W4_PARITY;
50853905Smckusick 		if (param & EVEN)
50953905Smckusick 			bit |= W4_EVEN;
51053905Smckusick 	}
51153905Smckusick 	switch (param & STOPBIT) {
51253905Smckusick 
51353905Smckusick 	case STOP1:
51453905Smckusick 		bit |= W4_STOP1;
51553905Smckusick 		break;
51653905Smckusick 
51753905Smckusick 	case STOP1_5:
51853905Smckusick 		bit |= W4_STOP1_5;
51953905Smckusick 		break;
52053905Smckusick 
52153905Smckusick 	case STOP2:
52253905Smckusick 		bit |= W4_STOP2;
52353905Smckusick 		break;
52453905Smckusick 
52553905Smckusick 	}
52653905Smckusick 	scc_write_reg(chan, WR4, bit);
52753905Smckusick 
52853905Smckusick 	/*
52953905Smckusick 	 * Receiver enable / receive character size / auto enable
53053905Smckusick 	 */
53153905Smckusick 	bit = (param & RXE ? W3_RxE : 0);
53253905Smckusick 	switch (param & CHAR_SIZE) {
53353905Smckusick 
53453905Smckusick 	case C5BIT:
53553905Smckusick 		break;
53653905Smckusick 
53753905Smckusick 	case C6BIT:
53853905Smckusick 		bit |= W3_Rx6BIT;
53953905Smckusick 		break;
54053905Smckusick 
54153905Smckusick 	case C7BIT:
54253905Smckusick 		bit |= W3_Rx7BIT;
54353905Smckusick 		break;
54453905Smckusick 
54553905Smckusick 	case C8BIT:
54653905Smckusick 		bit |= W3_Rx8BIT;
54753905Smckusick 		break;
54853905Smckusick 	}
54953905Smckusick #ifdef AUTO_ENABLE
55053905Smckusick 	if (param & AUTO_ENABLE)
55153905Smckusick 		bit |= W3_AUTO;
55253905Smckusick #endif /* AUTO_ENABLE */
55353905Smckusick 	scc_write_reg(chan, WR3, bit);
55453905Smckusick 
55553905Smckusick 	/*
55653905Smckusick 	 * Transmitter enable / transmit character size / RTS / DTR / BREAK
55753905Smckusick 	 */
55853905Smckusick 	bit = (param & TXE ? W5_TxE : 0);
55953905Smckusick 	switch (param & CHAR_SIZE) {
56053905Smckusick 
56153905Smckusick 	case C5BIT:
56253905Smckusick 		break;
56353905Smckusick 
56453905Smckusick 	case C6BIT:
56553905Smckusick 		bit |= W5_Tx6BIT;
56653905Smckusick 		break;
56753905Smckusick 
56853905Smckusick 	case C7BIT:
56953905Smckusick 		bit |= W5_Tx7BIT;
57053905Smckusick 		break;
57153905Smckusick 
57253905Smckusick 	case C8BIT:
57353905Smckusick 		bit |= W5_Tx8BIT;
57453905Smckusick 		break;
57553905Smckusick 	}
57653905Smckusick 	if (param & RTS)
57753905Smckusick 		bit |= W5_RTS;
57853905Smckusick 	if (param & DTR)
57953905Smckusick 		bit |= W5_DTR;
58053905Smckusick 	if (param & XBREAK)
58153905Smckusick 		bit |= W5_BREAK;
58253905Smckusick 	scc_write_reg(chan, WR5, bit);
58353905Smckusick 	scc->scc_param = param;
58453905Smckusick 	(void) splx(s);
58553905Smckusick 	return (0);
58653905Smckusick }
58753905Smckusick 
58853905Smckusick scc_get_param(chan)
58953905Smckusick 	int chan;
59053905Smckusick {
59153905Smckusick 	register Scc_channel *scc = &sccsw[chan];
59253905Smckusick 
59353905Smckusick 	scc->scc_param = (scc->scc_param & ~(RI|DSR)) | get_ri_dsr(chan);
59453905Smckusick 	return (scc->scc_param);
59553905Smckusick }
59653905Smckusick 
59753905Smckusick scc_get_status(chan)
59853905Smckusick 	int chan;
59953905Smckusick {
60053905Smckusick 
60153905Smckusick 	return (sccsw[chan].scc_status);
60253905Smckusick }
60353905Smckusick 
60453905Smckusick scc_set_status(chan, stat)
60553905Smckusick 	int chan, stat;
60653905Smckusick {
60753905Smckusick 
60853905Smckusick 	sccsw[chan].scc_status = stat;
60953905Smckusick 
61053905Smckusick 	return (0);
61153905Smckusick }
61253905Smckusick 
61353905Smckusick scc_flush(chan)
61453905Smckusick 	int chan;
61553905Smckusick {
61653905Smckusick 	register Scc_channel *scc = &sccsw[chan];
61753905Smckusick 
61853905Smckusick 	if (scc->scc_status & OACTIVE)
61953905Smckusick 		scc->scc_status |= OFLUSH;
62053905Smckusick 	else if (scc->x_dma.dma_count > 0) {
62153905Smckusick 		scc->x_dma.dma_count = 0;
62253905Smckusick #if NRS > 0
62353905Smckusick 		rsxint(chan);
62453905Smckusick #endif
62553905Smckusick 	}
62653905Smckusick 	return (0);
62753905Smckusick }
62853905Smckusick 
62953905Smckusick scc_start(chan)
63053905Smckusick 	int chan;
63153905Smckusick {
63253905Smckusick 	register Scc_channel *scc = &sccsw[chan];
63353905Smckusick 
63453905Smckusick 	if ((scc->scc_status & OACTIVE) == 0 && scc->x_dma.dma_count > 0) {
63553905Smckusick 		scc->scc_port->data = *(scc->x_dma.dma_addr)++;
63653905Smckusick 		SCCWAIT;
63753905Smckusick 		scc->x_dma.dma_count--;
63853905Smckusick 		scc->scc_status |= OACTIVE;
63953905Smckusick 	}
64053905Smckusick 	return (0);
64153905Smckusick }
64253905Smckusick 
64353905Smckusick scc_stop(chan)
64453905Smckusick 	int chan;
64553905Smckusick {
64653905Smckusick 	register Scc_channel *scc = &sccsw[chan];
64753905Smckusick 
64853905Smckusick 	if (scc->scc_status & OACTIVE)
64953905Smckusick 		scc->scc_status |= OSTOP;
65053905Smckusick 	return (0);
65153905Smckusick }
65253905Smckusick 
65353905Smckusick scc_write(chan, buf, count)
65453905Smckusick 	int chan;
65553905Smckusick 	caddr_t buf;
65653905Smckusick 	int count;
65753905Smckusick {
65853905Smckusick 	register Scc_channel *scc = &sccsw[chan];
65953905Smckusick 
66053905Smckusick 	if (count <= 0)
66153905Smckusick 		return (0);
66253905Smckusick 	scc->x_dma.dma_addr = buf;
66353905Smckusick 	scc->x_dma.dma_count = count;
66453905Smckusick 	scc_start(chan);
66553905Smckusick 	return (count);
66653905Smckusick }
66753905Smckusick 
66853905Smckusick scc_error_write(chan, buf, count)
66953905Smckusick 	int chan;
67053905Smckusick 	register char *buf;
67153905Smckusick 	register int count;
67253905Smckusick {
67353905Smckusick 	register int i;
67453905Smckusick 
67553905Smckusick 	for (i = 0; i < count; i++)
67653905Smckusick 		scc_putc(chan, *buf++);
67753905Smckusick 	return (i);
67853905Smckusick }
67953905Smckusick 
68053905Smckusick scc_reset(chan)
68153905Smckusick 	int chan;
68253905Smckusick {
68353905Smckusick 	register Scc_channel *scc = &sccsw[chan];
68453905Smckusick 
68553905Smckusick 	while (scc_getc(chan) != -1)
68653905Smckusick 		;
68753905Smckusick 	scc->scc_status &= ~CHAN_ACTIVE;
68853905Smckusick }
689