📄 dcm.c
字号:
/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * 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 Utah: $Hdr: dcm.c 1.29 92/01/21$ * * @(#)dcm.c 8.4 (Berkeley) 1/12/94 *//* * TODO: * Timeouts * Test console support. */#include "dcm.h"#if NDCM > 0/* * 98642/MUX */#include <sys/param.h>#include <sys/systm.h>#include <sys/ioctl.h>#include <sys/proc.h>#include <sys/tty.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/uio.h>#include <sys/kernel.h>#include <sys/syslog.h>#include <sys/time.h>#include <hp/dev/device.h>#include <hp300/dev/dcmreg.h>#include <machine/cpu.h>#include <hp300/hp300/isr.h>#ifndef DEFAULT_BAUD_RATE#define DEFAULT_BAUD_RATE 9600#endifint dcmprobe(), dcmintr(), dcmparam();void dcmstart();struct driver dcmdriver = { dcmprobe, "dcm",};#define NDCMLINE (NDCM*4)struct tty dcm_tty[NDCMLINE];struct modemreg *dcm_modem[NDCMLINE];char mcndlast[NDCMLINE]; /* XXX last modem status for line */int ndcm = NDCMLINE;int dcm_active;int dcmsoftCAR[NDCM];struct dcmdevice *dcm_addr[NDCM];struct isr dcmisr[NDCM];struct speedtab dcmspeedtab[] = { 0, BR_0, 50, BR_50, 75, BR_75, 110, BR_110, 134, BR_134, 150, BR_150, 300, BR_300, 600, BR_600, 1200, BR_1200, 1800, BR_1800, 2400, BR_2400, 4800, BR_4800, 9600, BR_9600, 19200, BR_19200, 38400, BR_38400, -1, -1};/* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */#define DCM_USPERCH(s) (10000000 / (s))/* * Per board interrupt scheme. 16.7ms is the polling interrupt rate * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms). */#define DIS_TIMER 0#define DIS_PERCHAR 1#define DIS_RESET 2int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */int dcminterval = 5; /* interval (secs) between checks */struct dcmischeme { int dis_perchar; /* non-zero if interrupting per char */ long dis_time; /* last time examined */ int dis_intr; /* recv interrupts during last interval */ int dis_char; /* characters read during last interval */} dcmischeme[NDCM];/* * Console support */#ifdef DCMCONSOLEint dcmconsole = DCMCONSOLE;#elseint dcmconsole = -1;#endifint dcmconsinit;int dcmdefaultrate = DEFAULT_BAUD_RATE;int dcmconbrdbusy = 0;int dcmmajor;extern struct tty *constty;#ifdef KGDB/* * Kernel GDB support */#include <machine/remote-sl.h>extern dev_t kgdb_dev;extern int kgdb_rate;extern int kgdb_debug_init;#endif/* #define DCMSTATS */#ifdef DEBUGint dcmdebug = 0x0;#define DDB_SIOERR 0x01#define DDB_PARAM 0x02#define DDB_INPUT 0x04#define DDB_OUTPUT 0x08#define DDB_INTR 0x10#define DDB_IOCTL 0x20#define DDB_INTSCHM 0x40#define DDB_MODEM 0x80#define DDB_OPENCLOSE 0x100#endif#ifdef DCMSTATS#define DCMRBSIZE 94#define DCMXBSIZE 24struct dcmstats { long xints; /* # of xmit ints */ long xchars; /* # of xmit chars */ long xempty; /* times outq is empty in dcmstart */ long xrestarts; /* times completed while xmitting */ long rints; /* # of recv ints */ long rchars; /* # of recv chars */ long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */ long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */} dcmstats[NDCM];#endif#define UNIT(x) minor(x)#define BOARD(x) (((x) >> 2) & 0x3f)#define PORT(x) ((x) & 3)#define MKUNIT(b,p) (((b) << 2) | (p))/* * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux, * the distribution panel uses "HP DCE" conventions. If requested via * the device flags, we swap the inputs to something closer to normal DCE, * allowing a straight-through cable to a DTE or a reversed cable * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected; * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect * DSR or make RTS work, though). The following gives the full * details of a cable from this mux panel to a modem: * * HP modem * name pin pin name * HP inputs: * "Rx" 2 3 Tx * CTS 4 5 CTS (only needed for CCTS_OFLOW) * DCD 20 8 DCD * "DSR" 9 6 DSR (unneeded) * RI 22 22 RI (unneeded) * * HP outputs: * "Tx" 3 2 Rx * "DTR" 6 not connected * "RTS" 8 20 DTR * "SR" 23 4 RTS (often not needed) */#define FLAG_STDDCE 0x10 /* map inputs if this bit is set in flags */#define hp2dce_in(ibits) (iconv[(ibits) & 0xf])static char iconv[16] = { 0, MI_DM, MI_CTS, MI_CTS|MI_DM, MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM, MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM, MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS, MI_RI|MI_CD|MI_CTS|MI_DM};dcmprobe(hd) register struct hp_device *hd;{ register struct dcmdevice *dcm; register int i; register int timo = 0; int s, brd, isconsole, mbits; dcm = (struct dcmdevice *)hd->hp_addr; if ((dcm->dcm_rsid & 0x1f) != DCMID) return (0); brd = hd->hp_unit; isconsole = (brd == BOARD(dcmconsole)); /* * XXX selected console device (CONSUNIT) as determined by * dcmcnprobe does not agree with logical numbering imposed * by the config file (i.e. lowest address DCM is not unit * CONSUNIT). Don't recognize this card. */ if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)]) return (0); /* * Empirically derived self-test magic */ s = spltty(); dcm->dcm_rsid = DCMRS; DELAY(50000); /* 5000 is not long enough */ dcm->dcm_rsid = 0; dcm->dcm_ic = IC_IE; dcm->dcm_cr = CR_SELFT; while ((dcm->dcm_ic & IC_IR) == 0) if (++timo == 20000) return (0); DELAY(50000) /* XXX why is this needed ???? */ while ((dcm->dcm_iir & IIR_SELFT) == 0) if (++timo == 400000) return (0); DELAY(50000) /* XXX why is this needed ???? */ if (dcm->dcm_stcon != ST_OK) { if (!isconsole) printf("dcm%d: self test failed: %x\n", brd, dcm->dcm_stcon); return (0); } dcm->dcm_ic = IC_ID; splx(s); hd->hp_ipl = DCMIPL(dcm->dcm_ic); dcm_addr[brd] = dcm; dcm_active |= 1 << brd; dcmsoftCAR[brd] = hd->hp_flags; dcmisr[brd].isr_ipl = hd->hp_ipl; dcmisr[brd].isr_arg = brd; dcmisr[brd].isr_intr = dcmintr; isrlink(&dcmisr[brd]);#ifdef KGDB if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) { if (dcmconsole == UNIT(kgdb_dev)) kgdb_dev = NODEV; /* can't debug over console port */#ifndef KGDB_CHEAT /* * The following could potentially be replaced * by the corresponding code in dcmcnprobe. */ else { (void) dcminit(kgdb_dev, kgdb_rate); if (kgdb_debug_init) { printf("dcm%d: ", UNIT(kgdb_dev)); kgdb_connect(1); } else printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev)); } /* end could be replaced */#endif }#endif if (dcmistype == DIS_TIMER) dcmsetischeme(brd, DIS_RESET|DIS_TIMER); else dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR); /* load pointers to modem control */ dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0; dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1; dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2; dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3; /* set DCD (modem) and CTS (flow control) on all ports */ if (dcmsoftCAR[brd] & FLAG_STDDCE) mbits = hp2dce_in(MI_CD|MI_CTS); else mbits = MI_CD|MI_CTS; for (i = 0; i < 4; i++) dcm_modem[MKUNIT(brd, i)]->mdmmsk = mbits; dcm->dcm_ic = IC_IE; /* turn all interrupts on */ /* * Need to reset baud rate, etc. of next print so reset dcmconsole. * Also make sure console is always "hardwired" */ if (isconsole) { dcmconsinit = 0; dcmsoftCAR[brd] |= (1 << PORT(dcmconsole)); } return (1);}/* ARGSUSED */#ifdef __STDC__dcmopen(dev_t dev, int flag, int mode, struct proc *p)#elsedcmopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;#endif{ register struct tty *tp; register int unit, brd; int error = 0, mbits; unit = UNIT(dev); brd = BOARD(unit); if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0) return (ENXIO); tp = &dcm_tty[unit]; tp->t_oproc = dcmstart; tp->t_param = dcmparam; tp->t_dev = dev; 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; } (void) dcmparam(tp, &tp->t_termios); ttsetwater(tp); } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) return (EBUSY); mbits = MO_ON; if (dcmsoftCAR[brd] & FLAG_STDDCE) mbits |= MO_SR; /* pin 23, could be used as RTS */ (void) dcmmctl(dev, mbits, DMSET); /* enable port */ if ((dcmsoftCAR[brd] & (1 << PORT(unit))) || (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)) tp->t_state |= TS_CARR_ON;#ifdef DEBUG if (dcmdebug & DDB_MODEM) printf("dcm%d: dcmopen port %d softcarr %c\n", brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0');#endif (void) spltty(); while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && (tp->t_state & TS_CARR_ON) == 0) { tp->t_state |= TS_WOPEN; if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0)) break; } (void) spl0();#ifdef DEBUG if (dcmdebug & DDB_OPENCLOSE) printf("dcmopen: u %x st %x fl %x\n", unit, tp->t_state, tp->t_flags);#endif if (error == 0) error = (*linesw[tp->t_line].l_open)(dev, tp); return (error);} /*ARGSUSED*/dcmclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ register struct tty *tp; int unit; unit = UNIT(dev); tp = &dcm_tty[unit]; (*linesw[tp->t_line].l_close)(tp, flag); if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || (tp->t_state&TS_ISOPEN) == 0) (void) dcmmctl(dev, MO_OFF, DMSET);#ifdef DEBUG if (dcmdebug & DDB_OPENCLOSE) printf("dcmclose: u %x st %x fl %x\n", unit, tp->t_state, tp->t_flags);#endif ttyclose(tp); return (0);} dcmread(dev, uio, flag) dev_t dev; struct uio *uio; int flag;{ register struct tty *tp; tp = &dcm_tty[UNIT(dev)]; return ((*linesw[tp->t_line].l_read)(tp, uio, flag));} dcmwrite(dev, uio, flag) dev_t dev; struct uio *uio; int flag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -