📄 scc.c
字号:
/*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)scc.c 8.2 (Berkeley) 11/30/93 *//* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */#include <scc.h>#if NSCC > 0/* * Intel 82530 dual usart chip driver. Supports the serial port(s) on the * Personal DECstation 5000/xx and DECstation 5000/1xx, plus the keyboard * and mouse on the 5000/1xx. (Don't ask me where the A channel signals * are on the 5000/xx.) * * See: Intel MicroCommunications Handbook, Section 2, pg. 155-173, 1992. */#include <sys/param.h>#include <sys/systm.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/proc.h>#include <sys/map.h>#include <sys/buf.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/uio.h>#include <sys/kernel.h>#include <sys/syslog.h>#include <machine/pmioctl.h>#include <pmax/dev/device.h>#include <pmax/dev/pdma.h>#include <pmax/dev/sccreg.h>#include <pmax/dev/fbreg.h>#include <pmax/pmax/cons.h>#include <pmax/pmax/pmaxtype.h>extern int pmax_boardtype;extern struct consdev cn_tab;extern void ttrstrt __P((void *));extern void KBDReset __P((dev_t, void (*)()));extern void MouseInit __P((dev_t, void (*)(), int (*)()));/* * Driver information for auto-configuration stuff. */int sccprobe(), sccopen(), sccparam(), sccGetc();void sccintr(), sccstart(), sccPutc();struct driver sccdriver = { "scc", sccprobe, 0, 0, sccintr,};#define NSCCLINE (NSCC*2)#define SCCUNIT(dev) (minor(dev) >> 1)#define SCCLINE(dev) (minor(dev) & 0x1)struct tty scc_tty[NSCCLINE];void (*sccDivertXInput)(); /* X windows keyboard input routine */void (*sccMouseEvent)(); /* X windows mouse motion event routine */void (*sccMouseButtons)(); /* X windows mouse buttons event routine */#ifdef DEBUGint debugChar;#endifstatic void scc_modem_intr(), sccreset();struct scc_softc { struct pdma scc_pdma[2]; struct { u_char wr1; u_char wr3; u_char wr4; u_char wr5; u_char wr14; } scc_wreg[2]; int scc_softCAR;} scc_softc[NSCC];struct speedtab sccspeedtab[] = { 0, 0, 50, 4606, 75, 3070, 110, 2093, 134, 1711, 150, 1534, 300, 766, 600, 382, 1200, 190, 1800, 126, 2400, 94, 4800, 46, 9600, 22, 19200, 10, 38400, 4, -1, -1};#ifndef PORTSELECTOR#define ISPEED TTYDEF_SPEED#define LFLAG TTYDEF_LFLAG#else#define ISPEED B4800#define LFLAG (TTYDEF_LFLAG & ~ECHO)#endif/* * Test to see if device is present. * Return true if found and initialized ok. */sccprobe(cp) register struct pmax_ctlr *cp;{ register struct scc_softc *sc; register struct pdma *pdp; register struct tty *tp; register int cntr; struct tty ctty; struct termios cterm; int s; if (cp->pmax_unit >= NSCC) return (0); if (badaddr(cp->pmax_addr, 2)) return (0); /* * For a remote console, wait a while for previous output to * complete. */ if (major(cn_tab.cn_dev) == SCCDEV && cn_tab.cn_screen == 0 && SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit) DELAY(10000); sc = &scc_softc[cp->pmax_unit]; pdp = &sc->scc_pdma[0]; /* init pseudo DMA structures */ tp = &scc_tty[cp->pmax_unit * 2]; for (cntr = 0; cntr < 2; cntr++) { pdp->p_addr = (void *)cp->pmax_addr; pdp->p_arg = (int)tp; pdp->p_fcn = (void (*)())0; tp->t_dev = (dev_t)((cp->pmax_unit << 1) | cntr); pdp++, tp++; } sc->scc_softCAR = cp->pmax_flags | 0x2; /* reset chip */ sccreset(sc); /* * Special handling for consoles. */ if (cn_tab.cn_screen) { if (cn_tab.cn_kbdgetc == sccGetc) { if (cp->pmax_unit == 1) { s = spltty(); ctty.t_dev = makedev(SCCDEV, SCCKBD_PORT); cterm.c_cflag = CS8; cterm.c_ospeed = cterm.c_ispeed = 4800; (void) sccparam(&ctty, &cterm); DELAY(10000);#ifdef notyet /* * For some reason doing this hangs the 3min * during booting. Fortunately the keyboard * works ok without it. */ KBDReset(ctty.t_dev, sccPutc);#endif DELAY(10000); splx(s); } else if (cp->pmax_unit == 0) { s = spltty(); ctty.t_dev = makedev(SCCDEV, SCCMOUSE_PORT); cterm.c_cflag = CS8 | PARENB | PARODD; cterm.c_ospeed = cterm.c_ispeed = 4800; (void) sccparam(&ctty, &cterm); DELAY(10000); MouseInit(ctty.t_dev, sccPutc, sccGetc); DELAY(10000); splx(s); } } } else if (SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit) { s = spltty(); ctty.t_dev = cn_tab.cn_dev; cterm.c_cflag = CS8; cterm.c_ospeed = cterm.c_ispeed = 9600; (void) sccparam(&ctty, &cterm); DELAY(1000); cn_tab.cn_disabled = 0; splx(s); } printf("scc%d at nexus0 csr 0x%x priority %d\n", cp->pmax_unit, cp->pmax_addr, cp->pmax_pri); return (1);}/* * Reset the chip. */static voidsccreset(sc) register struct scc_softc *sc;{ register scc_regmap_t *regs; register u_char val; regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr; /* * Chip once-only initialization * * NOTE: The wiring we assume is the one on the 3min: * * out A-TxD --> TxD keybd or mouse * in A-RxD --> RxD keybd or mouse * out A-DTR~ --> DTR comm * out A-RTS~ --> RTS comm * in A-CTS~ --> SI comm * in A-DCD~ --> RI comm * in A-SYNCH~--> DSR comm * out B-TxD --> TxD comm * in B-RxD --> RxD comm * in B-RxC --> TRxCB comm * in B-TxC --> RTxCB comm * out B-RTS~ --> SS comm * in B-CTS~ --> CTS comm * in B-DCD~ --> CD comm */ SCC_INIT_REG(regs, SCC_CHANNEL_A); SCC_INIT_REG(regs, SCC_CHANNEL_B); SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET); DELAY(50000); /*enough ? */ SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, 0); /* program the interrupt vector */ SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0); SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0); SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS); /* timing base defaults */ sc->scc_wreg[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16; sc->scc_wreg[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16; /* enable DTR, RTS and SS */ sc->scc_wreg[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS; sc->scc_wreg[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR; /* baud rates */ val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC; sc->scc_wreg[SCC_CHANNEL_B].wr14 = val; sc->scc_wreg[SCC_CHANNEL_A].wr14 = val; /* interrupt conditions */ val = SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE | SCC_WR1_EXT_IE; sc->scc_wreg[SCC_CHANNEL_A].wr1 = val; sc->scc_wreg[SCC_CHANNEL_B].wr1 = val;}sccopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ register struct scc_softc *sc; register struct tty *tp; register int unit, line; int s, error = 0; unit = SCCUNIT(dev); if (unit >= NSCC) return (ENXIO); line = SCCLINE(dev); sc = &scc_softc[unit]; if (sc->scc_pdma[line].p_addr == (void *)0) return (ENXIO); tp = &scc_tty[minor(dev)]; tp->t_oproc = sccstart; tp->t_param = sccparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp);#ifndef PORTSELECTOR if (tp->t_ispeed == 0) {#endif tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = LFLAG; tp->t_ispeed = tp->t_ospeed = ISPEED;#ifdef PORTSELECTOR tp->t_cflag |= HUPCL;#else }#endif (void) sccparam(tp, &tp->t_termios); ttsetwater(tp); } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0) return (EBUSY); (void) sccmctl(dev, DML_DTR, DMSET); s = spltty(); while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON)) { tp->t_state |= TS_WOPEN; if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0)) break; } splx(s); if (error) return (error); return ((*linesw[tp->t_line].l_open)(dev, tp));}/*ARGSUSED*/sccclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ register struct scc_softc *sc = &scc_softc[SCCUNIT(dev)]; register struct tty *tp; register int bit, line; tp = &scc_tty[minor(dev)]; line = SCCLINE(dev); if (sc->scc_wreg[line].wr5 & SCC_WR5_SEND_BREAK) { sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK; ttyoutput(0, tp); } (*linesw[tp->t_line].l_close)(tp, flag); if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) || !(tp->t_state & TS_ISOPEN)) (void) sccmctl(dev, 0, DMSET); return (ttyclose(tp));}sccread(dev, uio, flag) dev_t dev; struct uio *uio;{ register struct tty *tp; tp = &scc_tty[minor(dev)]; return ((*linesw[tp->t_line].l_read)(tp, uio, flag));}sccwrite(dev, uio, flag) dev_t dev; struct uio *uio;{ register struct tty *tp; tp = &scc_tty[minor(dev)]; return ((*linesw[tp->t_line].l_write)(tp, uio, flag));}/*ARGSUSED*/sccioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p;{ register struct scc_softc *sc; register struct tty *tp; int error, line; tp = &scc_tty[minor(dev)]; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error >= 0) return (error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) return (error); line = SCCLINE(dev); sc = &scc_softc[SCCUNIT(dev)]; switch (cmd) { case TIOCSBRK: sc->scc_wreg[line].wr5 |= SCC_WR5_SEND_BREAK; ttyoutput(0, tp); break; case TIOCCBRK: sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK; ttyoutput(0, tp); break; case TIOCSDTR: (void) sccmctl(dev, DML_DTR|DML_RTS, DMBIS); break; case TIOCCDTR: (void) sccmctl(dev, DML_DTR|DML_RTS, DMBIC); break; case TIOCMSET: (void) sccmctl(dev, *(int *)data, DMSET); break; case TIOCMBIS: (void) sccmctl(dev, *(int *)data, DMBIS); break; case TIOCMBIC: (void) sccmctl(dev, *(int *)data, DMBIC); break; case TIOCMGET: *(int *)data = sccmctl(dev, 0, DMGET); break; default: return (ENOTTY); } return (0);}sccparam(tp, t) register struct tty *tp; register struct termios *t;{ register struct scc_softc *sc; register scc_regmap_t *regs; register int line; register u_char value, wvalue; register int cflag = t->c_cflag; int ospeed; if (t->c_ispeed && t->c_ispeed != t->c_ospeed) return (EINVAL); sc = &scc_softc[SCCUNIT(tp->t_dev)]; line = SCCLINE(tp->t_dev); regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr; ospeed = ttspeedtab(t->c_ospeed, sccspeedtab); if (ospeed < 0) return (EINVAL); /* and copy to tty */ tp->t_ispeed = t->c_ispeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = cflag; /* * Handle console specially. */ if (cn_tab.cn_screen) { if (minor(tp->t_dev) == SCCKBD_PORT) { cflag = CS8; ospeed = ttspeedtab(4800, sccspeedtab); } else if (minor(tp->t_dev) == SCCMOUSE_PORT) { cflag = CS8 | PARENB | PARODD; ospeed = ttspeedtab(4800, sccspeedtab); } } else if (tp->t_dev == cn_tab.cn_dev) { cflag = CS8; ospeed = ttspeedtab(9600, sccspeedtab);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -