📄 mp.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Computer Consoles 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. * * @(#)mp.c 7.17 (Berkeley) 5/16/91 */#include "mp.h"#if NMP > 0/* * Multi Protocol Communications Controller (MPCC). * Asynchronous Terminal Protocol Support. */#include "sys/param.h"#include "sys/ioctl.h"#include "sys/tty.h"#include "sys/user.h"#include "sys/map.h"#include "sys/buf.h"#include "sys/conf.h"#include "sys/file.h"#include "sys/errno.h"#include "sys/syslog.h"#include "sys/vmmac.h"#include "sys/kernel.h"#include "sys/clist.h"#include "../include/pte.h"#include "../include/mtpr.h"#include "../vba/vbavar.h"#include "../vba/mpreg.h"#define MPCHUNK 16#define MPPORT(n) ((n) & 0xf)#define MPUNIT(n) ((n) >> 4)/* * Driver information for auto-configuration stuff. */int mpprobe(), mpattach(), mpintr();struct vba_device *mpinfo[NMP];long mpstd[] = { 0 };struct vba_driver mpdriver = { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo };int mpstart();int mpparam();struct mpevent *mpparam2();struct mpevent *mp_getevent();/* * The following structure is needed to deal with mpcc's convoluted * method for locating it's mblok structures (hold your stomach). * When an mpcc is reset at boot time it searches host memory * looking for a string that says ``ThIs Is MpCc''. The mpcc * then reads the structure to locate the pointer to it's mblok * structure (you can wretch now). */struct mpbogus { char s[12]; /* `ThIs Is MpCc'' */ u_char status; u_char unused; u_short magic; struct mblok *mb; struct mblok *mbloks[NMP]; /* can support at most 16 mpcc's */} mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' };/* * Software state per unit. */struct mpsoftc { u_int ms_ivec; /* interrupt vector */ u_int ms_softCAR; /* software carrier for async */ struct mblok *ms_mb; /* mpcc status area */ struct vb_buf ms_buf; /* vba resources for ms_mb */ struct hxmtl ms_hxl[MPMAXPORT];/* host transmit list */ struct asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */ char ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */} mp_softc[NMP];struct speedtab mpspeedtab[] = { 9600, M9600, /* baud rate = 9600 */ 4800, M4800, /* baud rate = 4800 */ 2400, M2400, /* baud rate = 2400 */ 1800, M1800, /* baud rate = 1800 */ 1200, M1200, /* baud rate = 1200 */ 600, M600, /* baud rate = 600 */ 300, M300, /* baud rate = 300 */ 200, M200, /* baud rate = 200 */ 150, M150, /* baud rate = 150 */ 134, M134_5, /* baud rate = 134.5 */ 110, M110, /* baud rate = 110 */ 75, M75, /* baud rate = 75 */ 50, M50, /* baud rate = 50 */ 0, M0, /* baud rate = 0 */ 2000, M2000, /* baud rate = 2000 */ 3600, M3600, /* baud rate = 3600 */ 7200, M7200, /* baud rate = 7200 */ 19200, M19200, /* baud rate = 19,200 */ 24000, M24000, /* baud rate = 24,000 */ 28400, M28400, /* baud rate = 28,400 */ 37800, M37800, /* baud rate = 37,800 */ 40300, M40300, /* baud rate = 40,300 */ 48000, M48000, /* baud rate = 48,000 */ 52000, M52000, /* baud rate = 52,000 */ 56800, M56800, /* baud rate = 56,800 */ EXTA, MEXTA, /* baud rate = Ext A */ EXTB, MEXTB, /* baud rate = Ext B */ -1, -1,};struct tty mp_tty[NMP*MPCHUNK];#ifndef lintint nmp = NMP*MPCHUNK;#endifint ttrstrt();mpprobe(reg, vi) caddr_t reg; struct vba_device *vi;{ register int br, cvec; register struct mpsoftc *ms;#ifdef lint br = 0; cvec = br; br = cvec; mpintr(0); mpdlintr(0);#endif if (badaddr(reg, 2)) return (0); ms = &mp_softc[vi->ui_unit]; /* * Allocate page tables and mblok * structure (mblok in non-cached memory). */ if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) { printf("mp%d: vbainit failed\n", vi->ui_unit); return (0); } ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf; ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit; /* XXX */ br = 0x14, cvec = ms->ms_ivec; /* XXX */ return (sizeof (*reg));}mpattach(vi) register struct vba_device *vi;{ register struct mpsoftc *ms = &mp_softc[vi->ui_unit]; ms->ms_softCAR = vi->ui_flags; /* * Setup pointer to mblok, initialize bogus * status block used by mpcc to locate the pointer * and then poke the mpcc to get it to search host * memory to find mblok pointer. */ mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf; *(short *)vi->ui_addr = 0x100; /* magic */}/* * Open an mpcc port. *//* ARGSUSED */mpopen(dev, mode) dev_t dev;{ register struct tty *tp; register struct mpsoftc *ms; int error, s, port, unit, mpu; struct vba_device *vi; struct mpport *mp; struct mpevent *ev; unit = minor(dev); mpu = MPUNIT(unit); if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) return (ENXIO); tp = &mp_tty[unit]; if (tp->t_state & TS_XCLUDE && u.u_uid != 0) return (EBUSY); ms = &mp_softc[mpu]; port = MPPORT(unit); if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC || ms->ms_mb->mb_status != MP_OPOPEN) return (ENXIO); mp = &ms->ms_mb->mb_port[port]; /* host mpcc struct */ s = spl8(); /* * serialize open and close events */ while ((mp->mp_flags & MP_PROGRESS) || ((tp->t_state & TS_WOPEN) && !(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL))) if (error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, ttopen, 0)) { splx(s); return (error); }restart: tp->t_state |= TS_WOPEN; tp->t_addr = (caddr_t)ms; tp->t_oproc = mpstart; tp->t_param = mpparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { ttychars(tp); if (tp->t_ispeed == 0) { tp->t_ispeed = TTYDEF_SPEED; tp->t_ospeed = TTYDEF_SPEED; tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_cflag = TTYDEF_CFLAG; } /* * Initialize port state: init MPCC interface * structures for port and setup modem control. */ error = mpportinit(ms, mp, port); if (error) goto bad; ev = mpparam2(tp, &tp->t_termios); if (ev == 0) { error = ENOBUFS; goto bad; } mp->mp_flags |= MP_PROGRESS; mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port); /* * wait for port to start */ while (mp->mp_proto != MPPROTO_ASYNC) if (error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, ttopen, 0)) goto bad; ttsetwater(tp); mp->mp_flags &= ~MP_PROGRESS; } while ((mode&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && (tp->t_state & TS_CARR_ON) == 0) { if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0)) goto bad; /* * a mpclose() might have disabled port. if so restart */ if (mp->mp_proto != MPPROTO_ASYNC) goto restart; tp->t_state |= TS_WOPEN; } error = (*linesw[tp->t_line].l_open)(dev,tp);done: splx(s); /* * wakeup those processes waiting for the open to complete */ wakeup((caddr_t)&tp->t_canq); return (error);bad: tp->t_state &= ~TS_WOPEN; goto done;}/* * Close an mpcc port. *//* ARGSUSED */mpclose(dev, flag) dev_t dev;{ register struct tty *tp; register struct mpport *mp; register struct mpevent *ev; int s, port, unit, error = 0; struct mblok *mb; unit = minor(dev); tp = &mp_tty[unit]; port = MPPORT(unit); mb = mp_softc[MPUNIT(unit)].ms_mb; mp = &mb->mb_port[port]; s = spl8(); if (mp->mp_flags & MP_PROGRESS) { if (mp->mp_flags & MP_REMBSY) { mp->mp_flags &= ~MP_REMBSY; splx(s); return (0); } while (mp->mp_flags & MP_PROGRESS) if (error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, ttclos, 0)) { splx(s); return (error); } } mp->mp_flags |= MP_PROGRESS; (*linesw[tp->t_line].l_close)(tp, flag); ev = mp_getevent(mp, unit, 1); if (ev == 0) { error = ENOBUFS; mp->mp_flags &= ~MP_PROGRESS; goto out; } if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) mpmodem(unit, MMOD_OFF); else mpmodem(unit, MMOD_ON); mpcmd(ev, EVCMD_CLOSE, 0, mb, port); error = ttyclose(tp);out: if (mp->mp_flags & MP_REMBSY) mpclean(mb, port); else while (mp->mp_flags & MP_PROGRESS && error == 0) error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, ttclos, 0); splx(s); return (error);}/* * Read from an mpcc port. */mpread(dev, uio, flag) dev_t dev; struct uio *uio;{ struct tty *tp; tp = &mp_tty[minor(dev)]; return ((*linesw[tp->t_line].l_read)(tp, uio, flag));}/* * Write to an mpcc port. */mpwrite(dev, uio, flag) dev_t dev; struct uio *uio;{ struct tty *tp; tp = &mp_tty[minor(dev)]; return ((*linesw[tp->t_line].l_write)(tp, uio, flag));}/* * Ioctl for a mpcc port */mpioctl(dev, cmd, data, flag) dev_t dev; caddr_t data;{ register struct tty *tp; register struct mpsoftc *ms; register struct mpport *mp; register struct mpevent *ev; int s, port, error, unit; struct mblok *mb; unit = minor(dev); tp = &mp_tty[unit]; ms = &mp_softc[MPUNIT(unit)]; mb = ms->ms_mb; port = MPPORT(unit); mp = &mb->mb_port[port]; if (mp->mp_proto != MPPROTO_ASYNC) return(ENXIO); 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: /* send break */ case TIOCCBRK: /* clear break */ s = spl8(); while (mp->mp_flags & MP_IOCTL) { if (error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, ttyout, 0)) { splx(s); return (error); } if (mp->mp_proto != MPPROTO_ASYNC) { splx(s); return (ENXIO); } } ev = mp_getevent(mp, unit, 0); if (ev) { mp->mp_flags |= MP_IOCTL; mpcmd(ev, EVCMD_IOCTL, (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port); } else error = ENOBUFS; splx(s); break; case TIOCSDTR: /* set dtr control line */ break; case TIOCCDTR: /* clear dtr control line */ break; default: error = ENOTTY; break; } return (error);}mpparam(tp, t) struct tty *tp; struct termios *t;{ register struct mpevent *ev; int unit = minor(tp->t_dev); struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; struct mblok *mb = ms->ms_mb; ev = mpparam2(tp, t); if (ev == 0) return (ENOBUFS); mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit)); return (0);} struct mpevent *mpparam2(tp, t) register struct tty *tp; struct termios *t;{ register struct mpevent *ev; register struct mpport *mp; int unit = minor(tp->t_dev); struct mblok *mb; struct mpsoftc *ms; register struct asyncparam *asp; int port, speedcode; ms = &mp_softc[MPUNIT(unit)]; mb = ms->ms_mb; port = MPPORT(unit); mp = &mb->mb_port[port]; ev = mp_getevent(mp, unit, 0); /* XXX */ speedcode = ttspeedtab(t->c_ospeed, mpspeedtab); if (ev == 0 || speedcode < 0) {printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n", MPUNIT(unit), port, ev, speedcode, t->c_ospeed); return (0); /* XXX */ } /* YUCK */ asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; asp->ap_xon = t->c_cc[VSTART]; asp->ap_xoff = t->c_cc[VSTOP]; if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) || (asp->ap_xoff == _POSIX_VDISABLE)) asp->ap_xena = MPA_DIS; else asp->ap_xena = MPA_ENA; asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS);#ifdef notnow if (t->t_cflag&CSIZE) == CS8) {#endif asp->ap_data = MPCHAR_8; asp->ap_parity = MPPAR_NONE;#ifdef notnow } else { asp->ap_data = MPCHAR_7; if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */ asp->ap_parity = MPPAR_ODD; else asp->ap_parity = MPPAR_EVEN; }#endif asp->ap_loop = MPA_DIS; /* disable loopback */ asp->ap_rtimer = A_RCVTIM; /* default receive timer */ if (t->c_ospeed == B110) asp->ap_stop = MPSTOP_2; else asp->ap_stop = MPSTOP_1; if (t->c_ospeed == 0) { tp->t_state |= TS_HUPCLS; setm(&asp->ap_modem, 0, DROP); seti(&asp->ap_intena, A_DCD);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -