📄 rs.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 * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. * * 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. * * from: $Hdr: rs.c,v 4.300 91/06/09 06:43:03 root Rel41 $ SONY * * @(#)rs.c 8.1 (Berkeley) 6/11/93 *//* rs.c 6.1 83/07/29 */#include "rs.h"#if NRS > 0/* * RS driver * */#if NBK > 0#include "bk.h"#endif#include <sys/param.h>#include <sys/conf.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/kernel.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/buf.h>#include <sys/malloc.h>#ifdef CPU_SINGLE#include <news3400/hbdev/hbvar.h>#else#include "../iop/iopvar.h"#endif#include <news3400/iop/rsreg.h>#include <news3400/sio/sccparam.h>#define RS_RXE RXE#define RS_TXE TXE#define RS_ON (RXE|TXE|RTS|DTR)#define RS_OFF TXE#define RS_RTS RTS#define RS_DTR DTR#define RS_CTS CTS#define RS_DCD DCD#define RS_DSR DSR#define RS_RI RI#define RS_BRK XBREAK#ifdef AUTO_ENABLE#define RS_AUTO_ENABLE AUTO_ENABLE#endif#ifdef CPU_SINGLE#define iop_device hb_device#define ii_unit hi_unit#define ii_flags hi_flags#define ii_alive hi_alive#endif/* * Definition of the driver for the auto-configuration program. */int rsprobe(), rsattach(), rsrint(), rsxint(), rssint();struct iop_device *rsinfo[NRS];#ifdef CPU_SINGLEstruct hb_driver rsdriver = { rsprobe, 0, rsattach, 0, 0, "rs", rsinfo };#elsestruct iop_driver rsdriver = { rsprobe, 0, rsattach, 0, "rs", rsinfo };#endif/* * Local variables for the driver */struct tty rs_tty[NRS*4];char rssoftCAR[NRS];int rs_flags[NRS*4];int rs_param[NRS*4];char rs_active[NRS*4];char rs_stopped[NRS*4];int rs_rate[NRS*4];int rs_average[NRS*4];char rs_timeout[NRS*4];char rs_watch;#ifndef lintint nrs = NRS*4; /* used by iostat */#endifextern int tty00_is_console;extern void rsstart();extern void ttrstrt();extern void rsctrl();#define RS_CARR(unit) (rssoftCAR[(unit) >> 2] & (1 << ((unit) & 03)))#define RS_FLAG(unit, flag) (rs_flags[unit] & (flag))#define RF_FLOWCTL 0x0010 /* use H/W flow control */#define RF_EXTCLK 0x0100 /* allow external clock */#define RF_NODELAY 0x1000 /* disable interrupt delay *//* * Routine for configuration *//*ARGSUSED*/rsprobe(ii) struct iop_device *ii;{ return (rs_probe(ii));}/* * Routine called to attach a rs. */rsattach(ii) register struct iop_device *ii;{ int i; rssoftCAR[ii->ii_unit] = ii->ii_flags; for (i = 0; i < 4; i++) rs_flags[ii->ii_unit * 4 + i] = (ii->ii_flags >> i) & (RF_FLOWCTL|RF_EXTCLK|RF_NODELAY); if (rs_watch == 0) { rs_watchdog(); rs_watch = 1; }}rs_watchdog(){ register int unit, s; for (unit = 0; unit < NRS*4; unit++) { if (rs_active[unit] == 0) continue; s = spltty(); rs_average[unit] = (rs_average[unit] * 7 + rs_rate[unit]) >> 3; rs_rate[unit] = 0; (void) splx(s); } timeout(rs_watchdog, (caddr_t)0, hz / 10);}/* * Open a RS line. Turn on this rs if this is the first use of it. *//*ARGSUSED*/rsopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ register int unit; register struct tty *tp; register struct iop_device *ii; int s; unit = minor(dev); if (unit >= NRS*4 || (ii = rsinfo[unit >> 2]) == 0 || ii->ii_alive == 0) return (ENXIO); if (rs_active[unit] == 0) { if (rs_init(unit) < 0) return (ENXIO); rs_enable(unit); rs_active[unit] = 1; } tp = &rs_tty[unit]; if (tp->t_state&TS_XCLUDE && curproc->p_ucred->cr_uid != 0) return (EBUSY); tp->t_addr = (caddr_t)0; tp->t_oproc = rsstart;#ifdef notyet /* KU:XXX */ tp->t_ctrlproc = rsctrl;#endif /* * If this is first open, initialze tty state to default. */ if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp); if (tp->t_ispeed == 0) { tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; } rsparam(tp, &tp->t_termios); ttsetwater(tp); } /* * Wait receiver and status interrupt */ /* * Wait for carrier, then process line discipline specific open. */ rsmctl(dev, RS_ON, DMSET); if (rs_param[unit] & DCD || RS_CARR(unit)) tp->t_state |= TS_CARR_ON; s = spltty(); /* spl5 -> spltty, 90/02/28 sak */ while ((tp->t_state & TS_CARR_ON) == 0) { tp->t_state |= TS_WOPEN; sleep((caddr_t)&tp->t_rawq, TTIPRI); }#ifdef notyet /* KU:XXX */ if (RS_FLAG(unit, RF_FLOWCTL)) { tp->t_state |= TS_HFLWCTL; rsmctl(dev, RS_AUTO_ENABLE, DMBIS); } else { tp->t_state &= ~TS_HFLWCTL; rsmctl(dev, RS_AUTO_ENABLE, DMBIC); }#endif (void) splx(s); return ((*linesw[tp->t_line].l_open)(dev, tp));}/* * Close a RS line. *//*ARGSUSED*/rsclose(dev, flag) dev_t dev; int flag;{ register struct tty *tp; register unit; unit = minor(dev); tp = &rs_tty[unit]; (*linesw[tp->t_line].l_close)(tp); (void) rsmctl(unit, RS_BRK, DMBIC); if (tp->t_cflag & HUPCL || (tp->t_state & TS_ISOPEN) == 0) (void) rsmctl(unit, RS_OFF, DMSET); ttyclose(tp); if (RS_FLAG(unit, RF_FLOWCTL)) (void)rsmctl(unit, RS_RTS, DMBIC);}rsread(dev, uio, flag) dev_t dev; struct uio *uio; int flag;{ register struct tty *tp; tp = &rs_tty[minor(dev)]; return ((*linesw[tp->t_line].l_read)(tp, uio, flag));}rswrite(dev, uio, flag) dev_t dev; struct uio *uio; int flag;{ register struct tty *tp; tp = &rs_tty[minor(dev)]; return ((*linesw[tp->t_line].l_write)(tp, uio, flag));}rsenable(unit) int unit;{ rs_timeout[unit] = 0; rs_enable(unit);}/* * RS receiver interrupt. */_rsrint(unit, buf, n) register int unit; register char *buf; register int n;{ register struct iop_device *ii; register struct tty *tp; register int (*rint)();#ifdef notyet /* KU:XXX */ intrcnt[INTR_RS0 + unit]++;#endif ii = rsinfo[unit >> 2]; if (ii == 0 || ii->ii_alive == 0) return; tp = &rs_tty[unit]; if ((tp->t_state & TS_ISOPEN) == 0) { wakeup((caddr_t)&tp->t_rawq); goto enable; } /* * Loop fetching characters from the silo for this * rs until there are no more in the silo. */ rint = linesw[tp->t_line].l_rint; while (--n >= 0) {#if NBK > 0 if (tp->t_line == NETLDISC) { c &= 0177; BKINPUT(c, tp); } else#endif /* NBK > 0 */ (*rint)(*buf++, tp); }enable: rs_rate[unit]++; if (rs_average[unit] >= 10 && RS_FLAG(unit, RF_NODELAY) == 0) { if (rs_timeout[unit] == 0) { rs_timeout[unit] = 1; timeout(rsenable, (caddr_t)unit, hz / 100); } } else rs_enable(unit);}/*ARGSUSED*/rsioctl(dev, cmd, data, flag) dev_t dev; caddr_t data;{ register struct tty *tp; register int unit = minor(dev); int error; tp = &rs_tty[unit]; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); if (error >= 0) return (error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) return (error); switch (cmd) { case TIOCSBRK: (void) rsmctl(dev, RS_BRK, DMBIS); break; case TIOCCBRK: (void) rsmctl(dev, RS_BRK, DMBIC); break; case TIOCSDTR: (void) rsmctl(dev, RS_DTR|RS_RTS, DMBIS); break; case TIOCCDTR: if (curproc->p_ucred->cr_uid && curproc->p_session->s_ttyp != tp) return (EACCES); (void) rsmctl(dev, RS_DTR|RS_RTS, DMBIC); break; case TIOCMSET: (void) rsmctl(dev, dmtors(*(int *)data), DMSET); break; case TIOCMBIS: (void) rsmctl(dev, dmtors(*(int *)data), DMBIS); break; case TIOCMBIC: (void) rsmctl(dev, dmtors(*(int *)data), DMBIC); break; case TIOCMGET: *(int *)data = rstodm(rsmctl(dev, 0, DMGET)); break; default: return (ENOTTY); } return (0);}dmtors(bits) register int bits;{ register int b; b = 0; if (bits & DML_LE) b |= RS_TXE|RS_RXE; if (bits & DML_DTR) b |= RS_DTR; if (bits & DML_RTS) b |= RS_RTS; if (bits & DML_CTS) b |= RS_CTS; if (bits & DML_CAR) b |= RS_DCD; if (bits & DML_RNG) b |= RS_RI; if (bits & DML_DSR) b |= RS_DSR;#ifdef AUTO_ENABLE if (bits & DML_USR) b |= RS_AUTO_ENABLE;#endif /* AUTO_ENABLE */ return(b);}rstodm(bits) register int bits;{ register int b; b = 0; if (bits & (RS_TXE|RS_RXE)) b |= DML_LE; if (bits & RS_DTR) b |= DML_DTR; if (bits & RS_RTS) b |= DML_RTS; if (bits & RS_CTS) b |= DML_CTS; if (bits & RS_DCD) b |= DML_CAR; if (bits & RS_RI) b |= DML_RNG; if (bits & RS_DSR) b |= DML_DSR;#ifdef AUTO_ENABLE if (bits & RS_AUTO_ENABLE) b |= DML_USR;#endif return(b);} /* * compat table */struct speedtab rsspeedtab[] = { 0, 0, 50, 1, 75, 2, 110, 3, 134, 4, 150, 5, 200, 6, 300, 7, 600, 8, 1200, 9, 1800, 10, 2400, 11, 4800, 12, 9600, 13, 19200, 14, 38400, 15, -1, -1};/* * Set parameters from open or stty into the RS hardware * registers. */rsparam(tp, t) register struct tty *tp; register struct termios *t;{ register int param; register int cflag = t->c_cflag; int unit = minor(tp->t_dev); int s; int ospeed = ttspeedtab(t->c_ospeed, rsspeedtab); /* check requested parameters */ if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) || (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6) return (EINVAL); /* and copy to tty */ tp->t_ispeed = t->c_ispeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = cflag; /* * Block interrupts so parameters will be set * before the line interrupts. */ s = spltty(); if (tp->t_ospeed == 0) { tp->t_cflag |= HUPCL; (void) rsmctl(unit, RS_OFF, DMSET); (void) splx(s); return (0); } param = rs_get_param(unit) & ~(CHAR_SIZE|PARITY|EVEN|STOPBIT|BAUD_RATE|NOCHECK); if ((cflag & CREAD) == 0) param &= ~RXE; if (cflag & CS6) param |= C6BIT; if (cflag & CS7) param |= C7BIT; if (cflag & PARENB) param |= PARITY; if ((cflag & PARODD) == 0) param |= EVEN; if ((tp->t_iflag & INPCK) == 0) param |= NOCHECK; if (cflag & CSTOPB) param |= STOP2; else param |= STOP1; rs_param[unit] = param | ospeed; if (RS_FLAG(unit, RF_EXTCLK)) rs_param[unit] |= EXTCLK_ENABLE; else rs_param[unit] &= ~EXTCLK_ENABLE; rs_set_param(unit, rs_param[unit]); (void) splx(s); return (0);}/* * RS transmitter interrupt. * Restart the idle line. */_rsxint(unit, count) int unit; int count;{ register struct tty *tp; register int s;#ifdef notyet /* KU:XXX */ intrcnt[INTR_RS0 + unit]++;#endif rs_stopped[unit] = 0; tp = &rs_tty[unit]; tp->t_state &= ~TS_BUSY; s = spltty(); if (tp->t_state & TS_FLUSH) tp->t_state &= ~TS_FLUSH;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -