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