📄 scc.c
字号:
#ifndef lintstatic char *sccsid = "@(#)scc.c 4.8 (ULTRIX) 1/22/91";#endif lint/************************************************************************ * * * Copyright (c) 1988,89 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************ */* * scc.c * * SCC SLU console driver * * Modification history * * 21-Jan-1991 - Randall Brown * Modified use of tc_isolate_memerr() to now use tc_memerr_status * struct. * * 06-Dec-1990 - Randall Brown * Added the call to tc_isolate_memerr() in the dma_xerror routine to * log error information about the memory error. * * 06-Nov-1990 - pgt * Added disabling of baud rate generator before time constants are * set. Fixed the setting of breaks. Modify dma interrupt routines * to do appropriate masking. Fixed handling of Speed Indicate. * Did general clean-up. * * 13-Sep-90 Joe Szczypek * Added new TURBOchannel console ROM support. osconsole environment * variable now returns 1 slot number if serial line, else 2 slot number * if graphics. Use this to determine how to do setup. Note that new * ROMs do not support multiple outputs... * * 7-Sept-1990 - pgt * Enabled modem control and break interrupts. Also fixed sccparam * and added macros to handle enabling and disabling of modem and * interrupts. * * 16-Aug-1990 - Randall Brown * Enable use of mouse and keyboard ports. * * 20-Feb-1990 - pgt (Philip Gapuz Te) * created file. * */#include "../machine/pte.h"#include "../h/param.h"#include "../h/systm.h"#include "../h/ioctl.h"#include "../h/tty.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/proc.h"#include "../h/map.h"#include "../h/buf.h"#include "../h/vm.h"#include "../h/conf.h"#include "../h/file.h"#include "../h/uio.h"#include "../h/kernel.h"#include "../h/devio.h"#include "../../machine/common/cpuconf.h"#include "../h/exec.h"#include "../h/kmalloc.h"#include "../h/sys_tpath.h"#include "../io/uba/ubavar.h" /* auto-config headers */#include "../machine/cpu.h"#include "../io/tc/ioasic.h"#include "../io/tc/sccreg.h"#include "../io/tc/slu.h"#include "../io/tc/vsxxx.h"#include "../io/tc/xcons.h"#include "../io/tc/tc.h"struct tty scc_tty[NSCCLINE]; /* tty structure */struct slu slu; struct scc_softc *sccsc; /* software controller struct for scc */u_char sccmodem[NSCCLINE]; /* keeps track of modem state */int scc_cbaud[NSCCLINE]; /* baud rate integer flag */int scc_brk[4]; /* break condition */struct timeval scctimestamp[NSCCLINE];char sccsoftCAR;char sccdefaultCAR;int scc_cnt = NSCCLINE;int sccprobe(), sccattach(), scc_dma_rint();int scc_dsr_check(), scc_tty_drop(), scc_cd_drop(); /* Modem */u_short sccstd[] = { 0 };struct uba_device *sccinfo[1];struct uba_driver sccdriver = { sccprobe, 0, sccattach, 0, sccstd, "scc", sccinfo };struct scc_softc scc_softc[1]; int sccstart(), scc_dma_xint(), sccbaudrate();int ttrstrt();int sccspeedi(); scc_half_speed();/* * Graphics device driver entry points. * Used to call graphics device driver as needed. */extern (*vs_gdopen)();extern (*vs_gdclose)();extern (*vs_gdread)();extern (*vs_gdwrite)();extern (*vs_gdselect)();extern (*vs_gdkint)();extern (*vs_gdioctl)();extern (*vs_gdstop)();extern int (*v_consgetc)();extern int (*v_consputc)();extern int prom_getenv();#define GRAPHIC_DEV 0x2 /* pick up from pm header file later */#define LINEMASK 0x03 /* line unit mask */int scc_other[4] = { 3, 2, 1, 0 };/* ioasic register bits */u_long scc_xdma_en[4] = { 0, 0, SSR_COMM1_XEN, SSR_COMM2_XEN};u_long scc_rdma_en[4] = { 0, 0, SSR_COMM1_REN, SSR_COMM2_REN};u_long scc_xint[4] = { 0, 0, SIR_COMM1_XINT, SIR_COMM2_XINT };u_long scc_rint[4] = { 0, 0, SIR_COMM1_RINT, SIR_COMM2_RINT };u_long scc_xerror[4] = { 0, 0, SIR_COMM1_XERROR, SIR_COMM2_XERROR };u_long scc_rerror[4] = { 0, 0, SIR_COMM1_RERROR, SIR_COMM2_RERROR };/* * Baud Rate Support * * When the baud rate on the right is specified, the line parameter register * is setup with the appropriate bits as specified in the left column. */#define BAUD_UNSUPPORTED 0 /* Device does not provide this baud rate */#define BAUD_SUPPORTED 1 /* Device does provide this baud rate *//* * The SCC manual provides a formula to compute the time constants for a * specified baudrate. For B110 and B134.5, the formula does not yield * whole integers. Thus, the chip baudrate in these two cases is very close * but not equal to the specified baudrate. */struct baud_support scc_speeds[] = { {0, 0, BAUD_UNSUPPORTED}, /* B0 */ {SCC_WR12_B50_LO, SCC_WR13_B50_HI, BAUD_SUPPORTED}, /* B50 */ {SCC_WR12_B75_LO, SCC_WR13_B75_HI, BAUD_SUPPORTED}, /* B75 */ {SCC_WR12_B110_LO, SCC_WR13_B110_HI, BAUD_SUPPORTED}, /* B110 */ {SCC_WR12_B134_5_LO, SCC_WR13_B134_5_HI, BAUD_SUPPORTED}, /* B134 */ {SCC_WR12_B150_LO, SCC_WR13_B150_HI, BAUD_SUPPORTED}, /* B150 */ {SCC_WR12_B200_LO, SCC_WR13_B200_HI, BAUD_SUPPORTED}, /* B200 */ {SCC_WR12_B300_LO, SCC_WR13_B300_HI, BAUD_SUPPORTED}, /* B300 */ {SCC_WR12_B600_LO, SCC_WR13_B600_HI, BAUD_SUPPORTED}, /* B600 */ {SCC_WR12_B1200_LO, SCC_WR13_B1200_HI, BAUD_SUPPORTED}, /* B1200 */ {SCC_WR12_B1800_LO, SCC_WR13_B1800_HI, BAUD_SUPPORTED}, /* B1800 */ {SCC_WR12_B2400_LO, SCC_WR13_B2400_HI, BAUD_SUPPORTED}, /* B2400 */ {SCC_WR12_B4800_LO, SCC_WR13_B4800_HI, BAUD_SUPPORTED}, /* B4800 */ {SCC_WR12_B9600_LO, SCC_WR13_B9600_HI, BAUD_SUPPORTED}, /* B9600 */ {SCC_WR12_B19200_LO, SCC_WR13_B19200_HI, BAUD_SUPPORTED}, /* EXTA */ {SCC_WR12_B38400_LO, SCC_WR13_B38400_HI, BAUD_SUPPORTED}, /* EXTB */};extern int consDev;#define SCC0_B_BASE (PHYS_TO_K1(0x1c100000))#define SCC0_A_BASE (PHYS_TO_K1(0x1c100008))#define SCC1_B_BASE (PHYS_TO_K1(0x1c180000))#define SCC1_A_BASE (PHYS_TO_K1(0x1c180008))#define SCC_READ(rsp, reg, val) { \ (rsp)->SCC_CMD = ((u_short)(reg))<<8; \ (val) = (((rsp)->SCC_CMD)>>8)&0xff; \ DELAY(10);\ }#define SCC_WRITE(rsp, reg, val) { \ (rsp)->SCC_CMD = ((u_short)(reg))<<8; \ (rsp)->SCC_CMD = ((u_short)(val))<<8; \ DELAY(10);\ }/* these macros can only set or clear one bit at a time */#define SCC_MSET(unit, bit) { \ sccsc->sc_saved_regs[(unit)].wr5 |= (bit); \ SCC_WRITE(sccsc->sc_regs[(unit)], SCC_WR5, \ sccsc->sc_saved_regs[(unit)].wr5); \ }#define SCC_MCLR(unit, bit) { \ sccsc->sc_saved_regs[(unit)].wr5 &= ~(bit); \ SCC_WRITE(sccsc->sc_regs[(unit)], SCC_WR5, \ sccsc->sc_saved_regs[(unit)].wr5); \ }#define SCC_MTEST(unit, bit) (((sccsc->sc_regs[(unit)]->SCC_CMD)>>8)&(bit))/* DTR makes use of the DTR of channel A, controlled by WR5 */#define SCC_SET_DTR(unit) SCC_MSET(scc_other[(unit)], SCC_WR5_DTR)#define SCC_CLR_DTR(unit) SCC_MCLR(scc_other[(unit)], SCC_WR5_DTR)#define SCC_SET_RTS(unit) SCC_MSET(scc_other[(unit)], SCC_WR5_RTS)#define SCC_CLR_RTS(unit) SCC_MCLR(scc_other[(unit)], SCC_WR5_RTS)#define SCC_SET_SS(unit) SCC_MSET((unit), SCC_WR5_RTS)#define SCC_CLR_SS(unit) SCC_MCLR((unit), SCC_WR5_RTS)#define SCC_SET_BRK(unit) SCC_MSET((unit), SCC_WR5_BRK)#define SCC_CLR_BRK(unit) SCC_MCLR((unit), SCC_WR5_BRK)#define SCC_DSR(unit) SCC_MTEST(scc_other[(unit)], SCC_RR0_SYNC)#define SCC_CTS(unit) SCC_MTEST((unit), SCC_RR0_CTS)#define SCC_DCD(unit) SCC_MTEST((unit), SCC_RR0_DCD)#define SCC_SI(unit) SCC_MTEST(scc_other[(unit)], SCC_RR0_CTS)#define SCC_RI(unit) SCC_MTEST(scc_other[(unit)], SCC_RR0_DCD)#define SCC_XMIT(unit) (SCC_DSR(scc_other[(unit)]) && SCC_CTS((unit)) && SCC_DCD((unit)))#define SCC_DTR(unit) ((sccsc->sc_saved_regs[scc_other[(unit)]].wr5)&SCC_WR5_DTR)#define SCC_RTS(unit) ((sccsc->sc_saved_regs[scc_other[(unit)]].wr5)&SCC_WR5_RTS)#define SCC_MODEM_ON(unit) { \ SCC_WRITE(sccsc->sc_regs[scc_other[(unit)]], SCC_WR15, SCC_WR15_SYNC_IE); \ sccsc->sc_regs[scc_other[(unit)]]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ sccsc->sc_regs[scc_other[(unit)]]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ SCC_WRITE(sccsc->sc_regs[(unit)], SCC_WR15, (SCC_WR15_CTS_IE|SCC_WR15_DCD_IE|SCC_WR15_BREAK_IE)); \ sccsc->sc_regs[(unit)]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ sccsc->sc_regs[(unit)]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ }#define SCC_MODEM_OFF(unit) { \ SCC_WRITE(sccsc->sc_regs[scc_other[(unit)]], SCC_WR15, 0x00); \ sccsc->sc_regs[scc_other[(unit)]]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ sccsc->sc_regs[scc_other[(unit)]]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ SCC_WRITE(sccsc->sc_regs[(unit)], SCC_WR15, SCC_WR15_BREAK_IE); \ sccsc->sc_regs[(unit)]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ sccsc->sc_regs[(unit)]->SCC_CMD = SCC_WR0_RESET_EXT_INT<<8; \ }#define SCC_INT_ON(unit) { \ if ((unit) == 0 || (unit) == 1) { \ sccsc->sc_saved_regs[(unit)].wr1 &= ~SCC_WR1_RINT; \ sccsc->sc_saved_regs[(unit)].wr1 |= SCC_WR1_RINT_ALL; \ SCC_WRITE(sccsc->sc_regs[(unit)], SCC_WR1, sccsc->sc_saved_regs[(unit)].wr1); \ } else { \ sccsc->sc_saved_regs[scc_other[(unit)]].wr1 |= SCC_WR1_EXT_IE; \ SCC_WRITE(sccsc->sc_regs[scc_other[(unit)]], SCC_WR1, sccsc->sc_saved_regs[scc_other[(unit)]].wr1); \ sccsc->sc_saved_regs[(unit)].wr1 &= ~SCC_WR1_RINT; \ sccsc->sc_saved_regs[(unit)].wr1 |= (SCC_WR1_RINT_SPC| SCC_WR1_EXT_IE| SCC_WR1_WDMA_EN); \ SCC_WRITE(sccsc->sc_regs[(unit)], SCC_WR1, sccsc->sc_saved_regs[(unit)].wr1); \ } \ }#define PRINT_SIGNALS() { cprintf("Modem signals: "); \ if (SCC_DSR(2)) cprintf(" DSR2 "); \ if (SCC_CTS(2)) cprintf(" CTS2 "); \ if (SCC_DCD(2)) cprintf(" CD2 "); \ if (SCC_SI(2)) cprintf(" SI2 "); \ if (SCC_RI(2)) cprintf(" RI2 "); \ if (SCC_DSR(3)) cprintf(" DSR3 "); \ if (SCC_CTS(3)) cprintf(" CTS3 "); \ if (SCC_DCD(3)) cprintf(" CD3 "); \ if (SCC_SI(3)) cprintf(" SI3 "); \ if (SCC_RI(3)) cprintf(" RI3 "); \ cprintf("\n"); }#define PRINT_SIR(sir) { \ if ((sir) & SIR_COMM1_RINT) cprintf("R1 "); \ if ((sir) & SIR_COMM2_RINT) cprintf("R2 "); \ if ((sir) & SIR_COMM1_XINT) cprintf("X1 "); \ if ((sir) & SIR_COMM2_XINT) cprintf("X2 "); \ }#define PRINT_SSR(line) { \ if ((*(u_int *)(0xbc040100)) & scc_rdma_en[(line)]) \ cprintf("SSR: RDMA Enabled: %d\n", (line)); \ }sccprobe(reg) int reg;{ /* the intialization is done through scc_cons_init, so * if we have gotten this far we are alive so return a 1 */ return(1);}sccattach(){ register struct scc_softc *sc = sccsc; register int i; register struct scc_reg *rsp, *rsp0; register struct scc_saved_reg *ssp, *ssp0; sccsoftCAR = 0xff; sccdefaultCAR = 0xff; scc_init(2); if (consDev == GRAPHIC_DEV) scc_init(3); for (i = 2; i < 4; i++) { SCC_CLR_DTR(i); /* clear modem control signals */ SCC_CLR_RTS(i); SCC_CLR_SS(i);/* * pgt: can not use IOC_CLR(reg, mask) to clear system interrupt register bits * because bits may change between the time the register value is saved and * the time it is written back with the mask. See ioasic.h for definition. */ IOC_WR(IOC_SIR, ~scc_rint[i]); IOC_WR(IOC_SIR, ~scc_xerror[i]); IOC_WR(IOC_SIR, ~scc_rerror[i]); /* set rdma ptr, enable rdma */ sc->ioc_regs[i]->RDMA_REG = (u_long)(svtophy(sc->rbuf[i][sc->rflag[i]] + SCC_HALF_PAGE - SCC_WORD) << 3); IOC_SET(IOC_SSR, scc_rdma_en[i]); }}/* * scc_init() sets the SCC modes */scc_init(unit) register int unit;{ register struct scc_softc *sc = sccsc; register struct scc_reg *rsp, *rsp0; register struct scc_saved_reg *ssp, *ssp0; register int line = unit; rsp = sc->sc_regs[line]; ssp = &sc->sc_saved_regs[line]; /* * set modes: * WR9 force hardware reset * WR4 line 1: odd parity, one stop bit, x16 clock * lines 0, 2, 3: ~no parity, one stop bit, x16 clock * WR1 ~W/DMA: DMA request, receive; parity is special condition * WR2 interrupt vector 0x00 * WR3 8 bits/char * WR5 8 bits/char * WR9 interrupt disabled 0x00 * WR10 NRZ * WR11 tx & rx clocks = brgen, TRxC input, RTxC ~no xtal * WR12 low time constant * WR13 hi time constant * baud rate: line 0 or 1: 4800 baud * line 2 or 3: 9600 baud * WR14 brgen source = pclk * line 2 or 3: channel B: ~DTR/REQ: request function, transmit * channel A: ~DTR/REQ: ~DTR function */ if (line == 0 || line == 1) { SCC_WRITE(rsp, SCC_WR9, SCC_WR9_RESETA); } else { SCC_WRITE(rsp, SCC_WR9, SCC_WR9_RESETB); }/* rpbfix : do we need to delay this long ???? */ DELAY(20); if (line == 1 ) { /* odd parity for mouse */ ssp->wr4 = ( SCC_WR4_PENABLE | SCC_WR4_ONESB | SCC_WR4_CLOCK16); SCC_WRITE(rsp, SCC_WR4, ssp->wr4); } else { /* no parity for mouse and comm. ports */ ssp->wr4 = (SCC_WR4_ONESB | SCC_WR4_CLOCK16); SCC_WRITE(rsp, SCC_WR4, ssp->wr4); } ssp->wr1 = (SCC_WR1_DMA_REQ | SCC_WR1_WDMA_RX | SCC_WR1_PSPC); SCC_WRITE(rsp, SCC_WR1, ssp->wr1); SCC_WRITE(rsp, SCC_WR2, 0xf0); /* interrupt vector 0x00 */ ssp->wr3 = SCC_WR3_RBITS8; SCC_WRITE(rsp, SCC_WR3, ssp->wr3); ssp->wr5 = SCC_WR5_TBITS8; SCC_WRITE(rsp, SCC_WR5, ssp->wr5); SCC_WRITE(rsp, SCC_WR9, 0x00); /* WR9 interrupt disabled */ SCC_WRITE(rsp, SCC_WR10, SCC_WR10_NRZ); /* * TRxC pin should be an input because we can not allow output from * the TRxC pin for asynchronous communication. See SCC manual. */ SCC_WRITE(rsp, SCC_WR11, SCC_WR11_TxC_BRGEN | SCC_WR11_RxC_BRGEN); if (line == 0 || line == 1) { /* keyboard or mouse 4800 BPS */ SCC_WRITE(rsp, SCC_WR12, SCC_WR12_B4800_LO); SCC_WRITE(rsp, SCC_WR13, SCC_WR13_B4800_HI); } else { /* 9600 BPS */ SCC_WRITE(rsp, SCC_WR12, SCC_WR12_B9600_LO); SCC_WRITE(rsp, SCC_WR13, SCC_WR13_B9600_HI); } if (line == 0 || line == 1) { /* channel A - keyboard or mouse */ ssp->wr14 = SCC_WR14_BRGEN_PCLK; SCC_WRITE(rsp, SCC_WR14, ssp->wr14); } else { /* * Communication ports 1 & 2 use the A channels of the mouse and * keyboard respectively. Since the ~DTR/REQ bit selects DTR when it * is zero, no need to do anything here. */ ssp->wr14 = (SCC_WR14_BRGEN_PCLK | SCC_WR14_REQ); SCC_WRITE(rsp, SCC_WR14, ssp->wr14); } SCC_WRITE(rsp, SCC_WR9, SCC_WR9_MIE);}scc_cons_init(){ extern int (*vcons_init[])(); extern int rex_base; int i; register struct scc_reg *rsp; register struct scc_softc *sc; register struct scc_saved_reg *ssp; int scc_mouse_init(), scc_mouse_putc(), scc_mouse_getc(); int scc_kbd_init(), scc_kbd_putc(), scc_kbd_getc(), scc_putc(); sccsc = &scc_softc[0]; sc = sccsc; sc->sc_regs[0] = (struct scc_reg *)SCC1_A_BASE; sc->sc_regs[1] = (struct scc_reg *)SCC0_A_BASE; sc->sc_regs[2] = (struct scc_reg *)SCC0_B_BASE; sc->sc_regs[3] = (struct scc_reg *)SCC1_B_BASE; sc->ioc_regs[2] = (struct ioc_reg *)IOC_COMM1_DMA_BASE; sc->ioc_regs[3] = (struct ioc_reg *)IOC_COMM2_DMA_BASE; for (i = 2; i < 4; i++) { KM_ALLOC(sc->tbuf[i], char *, SCC_PAGE_SIZE, KM_DEVBUF, KM_CLEAR); KM_ALLOC(sc->rbuf[i][0], char *, SCC_PAGE_SIZE, KM_DEVBUF, (KM_CLEAR | KM_NOCACHE)); KM_ALLOC(sc->rbuf[i][1], char *, SCC_PAGE_SIZE, KM_DEVBUF, (KM_CLEAR | KM_NOCACHE)); sc->rflag[i] = 0; } /* * * Query the prom. The prom can be set such that the user * could use either the alternate tty or the graphics console. * You get the graphics console if the first bit is set in * osconsole. The user sets the console variable
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -