home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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.
- *
- * @(#)vx.c 7.13 (Berkeley) 5/16/91
- */
-
- #include "vx.h"
- #if NVX > 0
- /*
- * VIOC-X driver
- */
- #ifdef VXPERF
- #define DOSCOPE
- #endif
-
- #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/proc.h"
- #include "sys/vm.h"
- #include "sys/kernel.h"
- #include "sys/syslog.h"
-
- #include "../include/pte.h"
-
- #include "../vba/vbavar.h"
- #include "../vba/vbaparam.h"
- #include "../vba/vxreg.h"
- #include "../vba/scope.h"
-
- #ifdef VX_DEBUG
- long vxintr4 = 0;
- #define VXERR4 1
- #define VXNOBUF 2
- long vxdebug = 0;
- #define VXVCM 1
- #define VXVCC 2
- #define VXVCX 4
- #endif
-
- /*
- * Interrupt type bits passed to vinthandl().
- */
- #define CMDquals 0 /* command completed interrupt */
- #define RSPquals 1 /* command response interrupt */
- #define UNSquals 2 /* unsolicited interrupt */
-
- #define VXUNIT(n) ((n) >> 4)
- #define VXPORT(n) ((n) & 0xf)
-
- struct tty vx_tty[NVX*16];
- #ifndef lint
- int nvx = NVX*16;
- #endif
- int vxstart(), ttrstrt();
- struct vxcmd *vobtain(), *nextcmd();
-
- /*
- * Driver information for auto-configuration stuff.
- */
- int vxprobe(), vxattach(), vxrint();
- struct vba_device *vxinfo[NVX];
- long vxstd[] = { 0 };
- struct vba_driver vxdriver =
- { vxprobe, 0, vxattach, 0, vxstd, "vx", vxinfo };
-
- struct vx_softc {
- struct vxdevice *vs_addr; /* H/W address */
- u_char vs_type; /* 0: viox-x/vioc-b, 1: vioc-bop */
- u_char vs_bop; /* bop board # for vioc-bop's */
- u_char vs_loport; /* low port nbr */
- u_char vs_hiport; /* high port nbr */
- u_short vs_nbr; /* viocx number */
- u_short vs_maxcmd; /* max number of concurrent cmds */
- u_short vs_silosiz; /* silo size */
- short vs_vers; /* vioc/pvioc version */
- #define VXV_OLD 0 /* PVIOCX | VIOCX */
- #define VXV_NEW 1 /* NPVIOCX | NVIOCX */
- short vs_state; /* controller state */
- #define VXS_READY 0 /* ready for commands */
- #define VXS_RESET 1 /* in process of reseting */
- u_short vs_softCAR; /* soft carrier */
- u_int vs_ivec; /* interrupt vector base */
- caddr_t vs_mricmd; /* most recent issued cmd */
- /* The remaining fields are zeroed on reset... */
- #define vs_zero vs_xmtcnt
- int vs_xmtcnt; /* xmit commands pending */
- struct vxcmd *vs_avail;/* next available command buffer */
- struct vxcmd *vs_build;
- struct vxcmd vs_lst[NVCXBUFS];
- struct vcmds vs_cmds;
- } vx_softc[NVX];
-
- struct speedtab vxspeedtab[] = {
- EXTA, V19200,
- EXTB, V19200,
- 19200, V19200,
- 9600, 13,
- 4800, 12,
- 2400, 11,
- 1800, 10,
- 1200, 9,
- 600, 8,
- 300, 7,
- 200, 6,
- 150, 5,
- 134, 4,
- 110, 3,
- 75, 2,
- 50, 1,
- 0, 0,
- -1, -1,
- };
-
- vxprobe(reg, vi)
- caddr_t reg;
- struct vba_device *vi;
- {
- register int br, cvec; /* must be r12, r11 */
- register struct vxdevice *vp;
- register struct vx_softc *vs;
- struct pte *dummypte;
-
- #ifdef lint
- br = 0; cvec = br; br = cvec;
- vackint(0); vunsol(0); vcmdrsp(0);
- #ifdef VX_DEBUG
- vxfreset(0);
- #endif
- #endif /* lint */
- /*
- * If on an HCX-9, the device has a 32-bit address,
- * and we receive that address so we can set up a map.
- * On VERSAbus devices, the address is 24-bit, and is
- * already mapped (into vmem[]) by autoconf.
- */
- if (!(reg >= vmem && reg < &vmem[ctob(VBIOSIZE)]) && /* XXX */
- !vbmemalloc(16, reg, &dummypte, ®)) {
- printf("vx%d: vbmemalloc failed.\n", vi->ui_unit);
- return(0);
- }
- vp = (struct vxdevice *)reg;
- if (badaddr((caddr_t)vp, 1))
- return (0);
- vp->v_fault = 0;
- vp->v_vioc = V_BSY;
- vp->v_hdwre = V_RESET; /* reset interrupt */
- DELAY(4000000);
- if (vp->v_fault != VXF_READY)
- return (0);
- vs = &vx_softc[vi->ui_unit];
- #ifdef notdef
- /*
- * Align vioc interrupt vector base to 4 vector
- * boundary and fitting in 8 bits (is this necessary,
- * wish we had documentation).
- */
- if ((vi->ui_hd->vh_lastiv -= 3) > 0xff)
- vi->ui_hd->vh_lastiv = 0xff;
- vs->vs_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x3;
- #else
- vs->vs_ivec = 0x40+vi->ui_unit*4;
- #endif
- br = 0x18, cvec = vs->vs_ivec; /* XXX */
- return (sizeof (struct vxdevice));
- }
-
- vxattach(vi)
- register struct vba_device *vi;
- {
- register struct vx_softc *vs = &vx_softc[vi->ui_unit];
-
- vs->vs_softCAR = vi->ui_flags;
- vs->vs_addr = (struct vxdevice *)vi->ui_addr;
- vxinit(vi->ui_unit, 1);
- }
-
- /*
- * Open a VX line.
- */
- /*ARGSUSED*/
- vxopen(dev, flag)
- dev_t dev;
- int flag;
- {
- register struct tty *tp; /* pointer to tty struct for port */
- register struct vx_softc *vs;
- register struct vba_device *vi;
- int unit, vx, s, error = 0;
- int vxparam();
-
- unit = minor(dev);
- vx = VXUNIT(unit);
- if (vx >= NVX || (vi = vxinfo[vx])== 0 || vi->ui_alive == 0)
- return (ENXIO);
- vs = &vx_softc[vx];
- tp = &vx_tty[unit];
- unit = VXPORT(unit);
- if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
- return (EBUSY);
- if (unit < vs->vs_loport || unit > vs->vs_hiport)
- return (ENXIO);
- tp->t_addr = (caddr_t)vs;
- tp->t_oproc = vxstart;
- tp->t_param = vxparam;
- tp->t_dev = dev;
- s = spl8();
- 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_lflag = TTYDEF_LFLAG;
- tp->t_cflag = TTYDEF_CFLAG;
- tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
- }
- vxparam(tp, &tp->t_termios);
- ttsetwater(tp);
- }
- vcmodem(dev, VMOD_ON);
- while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
- (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;
- }
- if (error == 0)
- error = (*linesw[tp->t_line].l_open)(dev,tp);
- splx(s);
- return (error);
- }
-
- /*
- * Close a VX line.
- */
- /*ARGSUSED*/
- vxclose(dev, flag, mode, p)
- dev_t dev;
- int flag, mode;
- struct proc *p;
- {
- register struct tty *tp;
- int unit, s, error = 0;
-
- unit = minor(dev);
- tp = &vx_tty[unit];
- s = spl8();
- (*linesw[tp->t_line].l_close)(tp, flag);
- if (tp->t_cflag & HUPCL || (tp->t_state & TS_ISOPEN) == 0)
- vcmodem(dev, VMOD_OFF);
- /* wait for the last response */
- while (tp->t_state&TS_FLUSH && error == 0)
- error = tsleep((caddr_t)&tp->t_state, TTOPRI | PCATCH,
- ttclos, 0);
- splx(s);
- if (error)
- return (error);
- return (ttyclose(tp));
- }
-
- /*
- * Read from a VX line.
- */
- vxread(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- {
- struct tty *tp = &vx_tty[minor(dev)];
-
- return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
- }
-
- /*
- * write on a VX line
- */
- vxwrite(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- {
- register struct tty *tp = &vx_tty[minor(dev)];
-
- return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
- }
-
- /*
- * VIOCX unsolicited interrupt.
- */
- vxrint(vx)
- register vx;
- {
- register struct tty *tp, *tp0;
- register struct vxdevice *addr;
- register struct vx_softc *vs;
- struct vba_device *vi;
- register int nc, c;
- register struct silo {
- u_char data, port;
- } *sp;
- short *osp;
- int overrun = 0;
-
- vi = vxinfo[vx];
- if (vi == 0 || vi->ui_alive == 0)
- return;
- addr = (struct vxdevice *)vi->ui_addr;
- switch (addr->v_uqual&037) {
- case 0:
- break;
- case 2:
- if (addr->v_ustat == VP_SILO_OFLOW)
- log(LOG_ERR, "vx%d: input silo overflow\n", vx);
- else {
- printf("vx%d: vc proc err, ustat %x\n",
- vx, addr->v_ustat);
- vxstreset(vx);
- }
- return;
- case 3:
- vcmintr(vx);
- return;
- case 4:
- return;
- default:
- printf("vx%d: vc uqual err, uqual %x\n", vx, addr->v_uqual);
- vxstreset(vx);
- return;
- }
- vs = &vx_softc[vx];
- if (vs->vs_vers == VXV_NEW)
- sp = (struct silo *)((caddr_t)addr + *(short *)addr->v_usdata);
- else
- sp = (struct silo *)((caddr_t)addr+VX_SILO+(addr->v_usdata[0]<<6));
- nc = *(osp = (short *)sp);
- if (nc == 0)
- return;
- if (vs->vs_vers == VXV_NEW && nc > vs->vs_silosiz) {
- printf("vx%d: %d exceeds silo size\n", nc);
- nc = vs->vs_silosiz;
- }
- tp0 = &vx_tty[vx*16];
- sp = (struct silo *)(((short *)sp)+1);
- for (; nc > 0; nc--, sp = (struct silo *)(((short *)sp)+1)) {
- c = sp->port & 017;
- if (vs->vs_loport > c || c > vs->vs_hiport)
- continue;
- tp = tp0 + c;
- if( (tp->t_state&TS_ISOPEN) == 0) {
- wakeup((caddr_t)&tp->t_rawq);
- continue;
- }
- c = sp->data&((tp->t_cflag&CSIZE)==CS8 ? 0xff : 0x7f);
- if ((sp->port&VX_RO) == VX_RO && !overrun) {
- log(LOG_ERR, "vx%d: receiver overrun\n", vi->ui_unit);
- overrun = 1;
- continue;
- }
- if (sp->port&VX_PE)
- c |= TTY_PE;
- if (sp->port&VX_FE)
- c |= TTY_FE;
- (*linesw[tp->t_line].l_rint)(c, tp);
- }
- *osp = 0;
- }
-
- /*
- * Ioctl for VX.
- */
- vxioctl(dev, cmd, data, flag)
- dev_t dev;
- caddr_t data;
- {
- register struct tty *tp;
- int error;
-
- tp = &vx_tty[minor(dev)];
- 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);
- return (ENOTTY);
- }
-
- vxparam(tp, t)
- struct tty *tp;
- struct termios *t;
- {
-
- return (vxcparam(tp, t, 1));
- }
-
- /*
- * Set parameters from open or stty into the VX hardware
- * registers.
- */
- vxcparam(tp, t, wait)
- struct tty *tp;
- struct termios *t;
- int wait;
- {
- register struct vx_softc *vs;
- register struct vxcmd *cp;
- int s, error = 0;
- int speedcode = ttspeedtab(t->c_ospeed, vxspeedtab);
-
- if (speedcode < 0 || (t->c_ispeed != t->c_ospeed && t->c_ispeed))
- return (EINVAL);
- vs = (struct vx_softc *)tp->t_addr;
- cp = vobtain(vs);
- s = spl8();
- /*
- * Construct ``load parameters'' command block
- * to setup baud rates, xon-xoff chars, parity,
- * and stop bits for the specified port.
- */
- cp->cmd = VXC_LPARAX;
- cp->par[1] = VXPORT(minor(tp->t_dev));
- /*
- * note: if the hardware does flow control, ^V doesn't work
- * to escape ^S
- */
- if (t->c_iflag&IXON) {
- if (t->c_cc[VSTART] == _POSIX_VDISABLE)
- cp->par[2] = 0;
- else
- cp->par[2] = t->c_cc[VSTART];
- if (t->c_cc[VSTOP] == _POSIX_VDISABLE)
- cp->par[3] = 0;
- else
- cp->par[3] = t->c_cc[VSTOP];
- } else
- cp->par[2] = cp->par[3] = 0;
- #ifdef notnow
- switch (t->c_cflag & CSIZE) { /* XXX */
- case CS8:
- #endif
- cp->par[4] = BITS8; /* 8 bits of data */
- #ifdef notnow
- break;
- case CS7:
- cp->par[4] = BITS7; /* 7 bits of data */
- break;
- case CS6:
- cp->par[4] = BITS6; /* 6 bits of data */
- break;
- case CS5:
- cp->par[4] = BITS5; /* 5 bits of data */
- break;
- }
- if ((t->c_cflag & PARENB) == 0) /* XXX */
- #endif
- cp->par[7] = VNOPARITY; /* no parity */
- #ifdef notnow
- else if (t->c_cflag&PARODD)
- cp->par[7] = VODDP; /* odd parity */
- else
- cp->par[7] = VEVENP; /* even parity */
- #endif
- cp->par[5] = (t->c_cflag&CSTOPB) ? VSTOP2 : VSTOP1;
- cp->par[6] = speedcode;
- if (vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd) && wait)
- error = tsleep((caddr_t)cp, TTIPRI | PCATCH, ttyout, 0);
- if ((t->c_ospeed)==0) {
- tp->t_cflag |= HUPCL;
- vcmodem(tp->t_dev, VMOD_OFF);
- }
- splx(s);
- return (error);
- }
-
- /*
- * VIOCX command response interrupt.
- * For transmission, restart output to any active port.
- * For all other commands, just clean up.
- */
- vxxint(vx, cp)
- register int vx;
- register struct vxcmd *cp;
- {
- register struct vxmit *vp;
- register struct tty *tp, *tp0;
- register struct vx_softc *vs;
-
- vs = &vx_softc[vx];
- cp = (struct vxcmd *)((long *)cp-1);
-
- switch (cp->cmd&0xff00) {
-
- case VXC_LIDENT: /* initialization complete */
- if (vs->vs_state == VXS_RESET) {
- vxfnreset(vx, cp);
- vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
- }
- cp->cmd++;
- return;
-
- case VXC_XMITDTA:
- case VXC_XMITIMM:
- break;
-
- case VXC_LPARAX:
- wakeup((caddr_t)cp);
- /* fall thru... */
- default: /* VXC_MDMCTL or VXC_FDTATOX */
- vrelease(vs, cp);
- if (vs->vs_state == VXS_RESET)
- vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
- return;
- }
- tp0 = &vx_tty[vx*16];
- vp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizeof (struct vxmit));
- for (; vp >= (struct vxmit *)cp->par; vp--) {
- tp = tp0 + (vp->line & 017);
- tp->t_state &= ~TS_BUSY;
- if (tp->t_state & TS_FLUSH) {
- tp->t_state &= ~TS_FLUSH;
- wakeup((caddr_t)&tp->t_state);
- } else
- ndflush(&tp->t_outq, vp->bcount+1);
- }
- vrelease(vs, cp);
- if (vs->vs_vers == VXV_NEW)
- (*linesw[tp->t_line].l_start)(tp);
- else {
- tp0 = &vx_tty[vx*16 + vs->vs_hiport];
- for(tp = &vx_tty[vx*16 + vs->vs_loport]; tp <= tp0; tp++)
- (*linesw[tp->t_line].l_start)(tp);
- if ((cp = nextcmd(vs)) != NULL) { /* command to send? */
- vs->vs_xmtcnt++;
- (void) vcmd(vx, (caddr_t)&cp->cmd);
- }
- }
- vs->vs_xmtcnt--;
- }
-
- /*
- * Force out partial XMIT command after timeout
- */
- vxforce(vs)
- register struct vx_softc *vs;
- {
- register struct vxcmd *cp;
- int s;
-
- s = spl8();
- if ((cp = nextcmd(vs)) != NULL) {
- vs->vs_xmtcnt++;
- (void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
- }
- splx(s);
- }
-
- /*
- * Start (restart) transmission on the given VX line.
- */
- vxstart(tp)
- register struct tty *tp;
- {
- register short n;
- register struct vx_softc *vs;
- int s, port;
-
- s = spl8();
- port = VXPORT(minor(tp->t_dev));
- vs = (struct vx_softc *)tp->t_addr;
- if ((tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) == 0) {
- if (tp->t_outq.c_cc <= tp->t_lowat) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_outq);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
- if (tp->t_outq.c_cc == 0) {
- splx(s);
- return;
- }
- scope_out(3);
- if (1 || !(tp->t_oflag&OPOST)) /* XXX */
- n = ndqb(&tp->t_outq, 0);
- else {
- n = ndqb(&tp->t_outq, 0200);
- if (n == 0) {
- n = getc(&tp->t_outq);
- timeout(ttrstrt, (caddr_t)tp, (n&0177)+6);
- tp->t_state |= TS_TIMEOUT;
- n = 0;
- }
- }
- if (n) {
- tp->t_state |= TS_BUSY;
- vsetq(vs, port, (char *)tp->t_outq.c_cf, n);
- }
- }
- splx(s);
- }
-
- /*
- * Stop output on a line.
- */
- vxstop(tp)
- register struct tty *tp;
- {
- int s;
-
- s = spl8();
- if (tp->t_state&TS_BUSY)
- if ((tp->t_state&TS_TTSTOP) == 0)
- tp->t_state |= TS_FLUSH;
- splx(s);
- }
-
- static int vxbbno = -1;
- /*
- * VIOCX Initialization. Makes free lists of command buffers.
- * Resets all viocx's. Issues a LIDENT command to each
- * viocx to establish interrupt vectors and logical port numbers.
- */
- vxinit(vx, wait)
- register int vx;
- int wait;
- {
- register struct vx_softc *vs;
- register struct vxdevice *addr;
- register struct vxcmd *cp;
- register char *resp;
- register int j;
- char type, *typestring;
-
- vs = &vx_softc[vx];
- addr = vs->vs_addr;
- type = addr->v_ident;
- vs->vs_vers = (type&VXT_NEW) ? VXV_NEW : VXV_OLD;
- if (vs->vs_vers == VXV_NEW)
- vs->vs_silosiz = addr->v_maxsilo;
- switch (type) {
-
- case VXT_VIOCX:
- case VXT_VIOCX|VXT_NEW:
- typestring = "VIOC-X";
- /* set soft carrier for printer ports */
- for (j = 0; j < 16; j++)
- if (vs->vs_softCAR & (1 << j) ||
- addr->v_portyp[j] == VXT_PARALLEL) {
- vs->vs_softCAR |= 1 << j;
- addr->v_dcd |= 1 << j;
- }
- break;
-
- case VXT_PVIOCX:
- case VXT_PVIOCX|VXT_NEW:
- typestring = "VIOC-X (old connector panel)";
- break;
- case VXT_VIOCBOP: /* VIOC-BOP */
- vs->vs_type = 1;
- vs->vs_bop = ++vxbbno;
- printf("VIOC-BOP no. %d at %x\n", vs->vs_bop, addr);
- goto unsup;
- default:
- printf("vx%d: unknown type %x\n", vx, type);
- unsup:
- vxinfo[vx]->ui_alive = 0;
- return;
- }
- vs->vs_nbr = vx; /* assign board number */
- vs->vs_maxcmd = (vs->vs_vers == VXV_NEW) ? 24 : 4;
- /*
- * Initialize all cmd buffers by linking them
- * into a free list.
- */
- for (j = 0; j < NVCXBUFS; j++) {
- cp = &vs->vs_lst[j];
- cp->c_fwd = &vs->vs_lst[j+1];
- }
- vs->vs_avail = &vs->vs_lst[0]; /* set idx to 1st free buf */
- cp->c_fwd = (struct vxcmd *)0; /* mark last buf in free list */
-
- /*
- * Establish the interrupt vectors and define the port numbers.
- */
- cp = vobtain(vs);
- cp->cmd = VXC_LIDENT;
- cp->par[0] = vs->vs_ivec; /* ack vector */
- cp->par[1] = cp->par[0]+1; /* cmd resp vector */
- cp->par[3] = cp->par[0]+2; /* unsol intr vector */
- cp->par[4] = 15; /* max ports, no longer used */
- cp->par[5] = 0; /* set 1st port number */
- (void) vcmd(vx, (caddr_t)&cp->cmd);
- if (!wait)
- return;
-
- for (j = 0; cp->cmd == VXC_LIDENT && j < 4000000; j++)
- ;
- if (j >= 4000000)
- printf("vx%d: didn't respond to LIDENT\n", vx);
-
- /* calculate address of response buffer */
- resp = (char *)addr + (addr->v_rspoff&0x3fff);
- if (resp[0] != 0 && (resp[0]&0177) != 3) {
- vrelease(vs, cp); /* init failed */
- return;
- }
- vs->vs_loport = cp->par[5];
- vs->vs_hiport = cp->par[7];
- printf("vx%d: %s%s, ports %d-%d\n", vx,
- (vs->vs_vers == VXV_NEW) ? "" : "old ", typestring,
- vs->vs_loport, vs->vs_hiport);
- vrelease(vs, cp);
- }
-
- /*
- * Obtain a command buffer
- */
- struct vxcmd *
- vobtain(vs)
- register struct vx_softc *vs;
- {
- register struct vxcmd *p;
- int s;
-
- s = spl8();
- p = vs->vs_avail;
- if (p == (struct vxcmd *)0) {
- #ifdef VX_DEBUG
- if (vxintr4&VXNOBUF)
- vxintr4 &= ~VXNOBUF;
- #endif
- printf("vx%d: no buffers\n", vs->vs_nbr);
- vxstreset(vs->vs_nbr);
- splx(s);
- return (vobtain(vs));
- }
- vs->vs_avail = p->c_fwd;
- splx(s);
- return ((struct vxcmd *)p);
- }
-
- /*
- * Release a command buffer
- */
- vrelease(vs, cp)
- register struct vx_softc *vs;
- register struct vxcmd *cp;
- {
- int s;
-
- #ifdef VX_DEBUG
- if (vxintr4&VXNOBUF)
- return;
- #endif
- s = spl8();
- cp->c_fwd = vs->vs_avail;
- vs->vs_avail = cp;
- splx(s);
- }
-
- struct vxcmd *
- nextcmd(vs)
- register struct vx_softc *vs;
- {
- register struct vxcmd *cp;
- int s;
-
- s = spl8();
- cp = vs->vs_build;
- vs->vs_build = (struct vxcmd *)0;
- splx(s);
- return (cp);
- }
-
- /*
- * Assemble transmits into a multiple command;
- * up to 8 transmits to 8 lines can be assembled together
- * (on PVIOCX only).
- */
- vsetq(vs, line, addr, n)
- register struct vx_softc *vs;
- caddr_t addr;
- {
- register struct vxcmd *cp;
- register struct vxmit *mp;
-
- /*
- * Grab a new command buffer or append
- * to the current one being built.
- */
- cp = vs->vs_build;
- if (cp == (struct vxcmd *)0) {
- cp = vobtain(vs);
- vs->vs_build = cp;
- cp->cmd = VXC_XMITDTA;
- } else {
- if ((cp->cmd & 07) == 07 || vs->vs_vers == VXV_NEW) {
- printf("vx%d: setq overflow\n", vs-vx_softc);
- vxstreset((int)vs->vs_nbr);
- return;
- }
- cp->cmd++;
- }
- /*
- * Select the next vxmit buffer and copy the
- * characters into the buffer (if there's room
- * and the device supports ``immediate mode'',
- * or store an indirect pointer to the data.
- */
- mp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizeof (struct vxmit));
- mp->bcount = n-1;
- mp->line = line;
- if (vs->vs_vers == VXV_NEW && n <= sizeof (mp->ostream)) {
- cp->cmd = VXC_XMITIMM;
- bcopy(addr, mp->ostream, (unsigned)n);
- } else {
- /* get system address of clist block */
- addr = (caddr_t)vtoph((struct proc *)0, (unsigned)addr);
- bcopy((caddr_t)&addr, mp->ostream, sizeof (addr));
- }
- /*
- * We send the data immediately if a VIOCX,
- * the command buffer is full, or if we've nothing
- * currently outstanding. If we don't send it,
- * set a timeout to force the data to be sent soon.
- */
- if (vs->vs_vers == VXV_NEW || (cp->cmd & 07) == 7 ||
- vs->vs_xmtcnt == 0) {
- vs->vs_xmtcnt++;
- (void) vcmd((int)vs->vs_nbr, (char *)&cp->cmd);
- vs->vs_build = 0;
- } else
- timeout(vxforce, (caddr_t)vs, 3);
- }
-
- /*
- * Write a command out to the VIOC
- */
- vcmd(vx, cmdad)
- register int vx;
- register caddr_t cmdad;
- {
- register struct vcmds *cp;
- register struct vx_softc *vs = &vx_softc[vx];
- int s;
-
- s = spl8();
- /*
- * When the vioc is resetting, don't process
- * anything other than VXC_LIDENT commands.
- */
- if (vs->vs_state == VXS_RESET && cmdad != NULL) {
- struct vxcmd *vcp = (struct vxcmd *)(cmdad-sizeof (vcp->c_fwd));
-
- if (vcp->cmd != VXC_LIDENT) {
- vrelease(vs, vcp);
- return (0);
- }
- }
- cp = &vs->vs_cmds;
- if (cmdad != (caddr_t)0) {
- cp->cmdbuf[cp->v_fill] = cmdad;
- if (++cp->v_fill >= VC_CMDBUFL)
- cp->v_fill = 0;
- if (cp->v_fill == cp->v_empty) {
- printf("vx%d: cmd q overflow\n", vx);
- vxstreset(vx);
- splx(s);
- return (0);
- }
- cp->v_cmdsem++;
- }
- if (cp->v_cmdsem && cp->v_curcnt < vs->vs_maxcmd) {
- cp->v_cmdsem--;
- cp->v_curcnt++;
- vinthandl(vx, ((V_BSY|CMDquals) << 8)|V_INTR);
- }
- splx(s);
- return (1);
- }
-
- /*
- * VIOC acknowledge interrupt. The VIOC has received the new
- * command. If no errors, the new command becomes one of 16 (max)
- * current commands being executed.
- */
- vackint(vx)
- register vx;
- {
- register struct vxdevice *vp;
- register struct vcmds *cp;
- struct vx_softc *vs;
- int s;
-
- scope_out(5);
- vs = &vx_softc[vx];
- if (vs->vs_type) /* Its a BOP */
- return;
- s = spl8();
- vp = vs->vs_addr;
- cp = &vs->vs_cmds;
- if (vp->v_vcid&V_ERR) {
- register char *resp;
- register i;
-
- printf("vx%d: ackint error type %x v_dcd %x\n", vx,
- vp->v_vcid & 07, vp->v_dcd & 0xff);
- resp = (char *)vs->vs_mricmd;
- for (i = 0; i < 16; i++)
- printf("%x ", resp[i]&0xff);
- printf("\n");
- splx(s);
- vxstreset(vx);
- return;
- }
- if ((vp->v_hdwre&017) == CMDquals) {
- #ifdef VX_DEBUG
- if (vxintr4 & VXERR4) { /* causes VIOC INTR ERR 4 */
- struct vxcmd *cp1, *cp0;
-
- cp0 = (struct vxcmd *)
- ((caddr_t)cp->cmdbuf[cp->v_empty]-sizeof (cp0->c_fwd));
- if (cp0->cmd == VXC_XMITDTA || cp0->cmd == VXC_XMITIMM) {
- cp1 = vobtain(vs);
- *cp1 = *cp0;
- vxintr4 &= ~VXERR4;
- (void) vcmd(vx, &cp1->cmd);
- }
- }
- #endif
- cp->v_curcmd[vp->v_vcid & VCMDLEN-1] = cp->cmdbuf[cp->v_empty];
- if (++cp->v_empty >= VC_CMDBUFL)
- cp->v_empty = 0;
- }
- if (++cp->v_itrempt >= VC_IQLEN)
- cp->v_itrempt = 0;
- vintempt(vx);
- splx(s);
- (void) vcmd(vx, (caddr_t)0); /* queue next cmd, if any */
- }
-
- /*
- * Command Response interrupt. The Vioc has completed
- * a command. The command may now be returned to
- * the appropriate device driver.
- */
- vcmdrsp(vx)
- register vx;
- {
- register struct vxdevice *vp;
- register struct vcmds *cp;
- register caddr_t cmd;
- register struct vx_softc *vs;
- register char *resp;
- register k;
- register int s;
-
- scope_out(6);
- vs = &vx_softc[vx];
- if (vs->vs_type) { /* Its a BOP */
- printf("vx%d: vcmdrsp interrupt\n", vx);
- return;
- }
- s = spl8();
- vp = vs->vs_addr;
- cp = &vs->vs_cmds;
- resp = (char *)vp + (vp->v_rspoff&0x7fff);
- if (((k = resp[1])&V_UNBSY) == 0) {
- printf("vx%d: cmdresp debug\n", vx);
- splx(s);
- vxstreset(vx);
- return;
- }
- k &= VCMDLEN-1;
- cmd = cp->v_curcmd[k];
- cp->v_curcmd[k] = (caddr_t)0;
- cp->v_curcnt--;
- k = *((short *)&resp[4]); /* cmd operation code */
- if ((k&0xff00) == VXC_LIDENT) /* want hiport number */
- for (k = 0; k < VRESPLEN; k++)
- cmd[k] = resp[k+4];
- resp[1] = 0;
- vxxint(vx, (struct vxcmd *)cmd);
- if (vs->vs_state == VXS_READY)
- vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
- splx(s);
- }
-
- /*
- * Unsolicited interrupt.
- */
- vunsol(vx)
- register vx;
- {
- register struct vxdevice *vp;
- struct vx_softc *vs;
- int s;
-
- scope_out(1);
- vs = &vx_softc[vx];
- if (vs->vs_type) { /* Its a BOP */
- printf("vx%d: vunsol from BOP\n", vx);
- return;
- }
- s = spl8();
- vp = vs->vs_addr;
- if (vp->v_uqual&V_UNBSY) {
- vxrint(vx);
- vinthandl(vx, ((V_BSY|UNSquals) << 8)|V_INTR);
- #ifdef notdef
- } else {
- printf("vx%d: unsolicited interrupt error\n", vx);
- splx(s);
- vxstreset(vx);
- #endif
- }
- splx(s);
- }
-
- /*
- * Enqueue an interrupt.
- */
- vinthandl(vx, item)
- register int vx;
- register item;
- {
- register struct vcmds *cp;
- int empty;
-
- cp = &vx_softc[vx].vs_cmds;
- empty = (cp->v_itrfill == cp->v_itrempt);
- cp->v_itrqueu[cp->v_itrfill] = item;
- if (++cp->v_itrfill >= VC_IQLEN)
- cp->v_itrfill = 0;
- if (cp->v_itrfill == cp->v_itrempt) {
- printf("vx%d: interrupt q overflow\n", vx);
- vxstreset(vx);
- } else if (empty)
- vintempt(vx);
- }
-
- vintempt(vx)
- int vx;
- {
- register struct vcmds *cp;
- register struct vxdevice *vp;
- register struct vx_softc *vs;
- register short item;
- register short *intr;
-
- vs = &vx_softc[vx];
- vp = vs->vs_addr;
- if (vp->v_vioc&V_BSY)
- return;
- cp = &vs->vs_cmds;
- if (cp->v_itrempt == cp->v_itrfill)
- return;
- item = cp->v_itrqueu[cp->v_itrempt];
- intr = (short *)&vp->v_vioc;
- switch ((item >> 8)&03) {
-
- case CMDquals: { /* command */
- int phys;
-
- if (cp->v_empty == cp->v_fill || vp->v_vcbsy&V_BSY)
- break;
- vs->vs_mricmd = (caddr_t)cp->cmdbuf[cp->v_empty];
- phys = vtoph((struct proc *)0,
- (unsigned)cp->cmdbuf[cp->v_empty]);
- vp->v_vcp[0] = ((short *)&phys)[0];
- vp->v_vcp[1] = ((short *)&phys)[1];
- vp->v_vcbsy = V_BSY;
- *intr = item;
- scope_out(4);
- break;
- }
-
- case RSPquals: /* command response */
- *intr = item;
- scope_out(7);
- break;
-
- case UNSquals: /* unsolicited interrupt */
- vp->v_uqual = 0;
- *intr = item;
- scope_out(2);
- break;
- }
- }
-
- /*
- * Start a reset on a vioc after error (hopefully)
- */
- vxstreset(vx)
- register int vx;
- {
- register struct vx_softc *vs;
- register struct vxdevice *vp;
- register struct vxcmd *cp;
- register int j;
- extern int vxinreset();
- int s;
-
- vs = &vx_softc[vx];
- s = spl8();
- if (vs->vs_state == VXS_RESET) { /* avoid recursion */
- splx(s);
- return;
- }
- vp = vs->vs_addr;
- /*
- * Zero out the vioc structures, mark the vioc as being
- * reset, reinitialize the free command list, reset the vioc
- * and start a timer to check on the progress of the reset.
- */
- bzero((caddr_t)&vs->vs_zero,
- (unsigned)((caddr_t)(vs + 1) - (caddr_t)&vs->vs_zero));
-
- /*
- * Setting VXS_RESET prevents others from issuing
- * commands while allowing currently queued commands to
- * be passed to the VIOC.
- */
- vs->vs_state = VXS_RESET;
- /* init all cmd buffers */
- for (j = 0; j < NVCXBUFS; j++) {
- cp = &vs->vs_lst[j];
- cp->c_fwd = &vs->vs_lst[j+1];
- }
- vs->vs_avail = &vs->vs_lst[0];
- cp->c_fwd = (struct vxcmd *)0;
- printf("vx%d: reset...", vx);
- vp->v_fault = 0;
- vp->v_vioc = V_BSY;
- vp->v_hdwre = V_RESET; /* generate reset interrupt */
- timeout(vxinreset, (caddr_t)vx, hz*5);
- splx(s);
- }
-
- /* continue processing a reset on a vioc after an error (hopefully) */
- vxinreset(vx)
- int vx;
- {
- register struct vxdevice *vp;
- int s = spl8();
-
- vp = vx_softc[vx].vs_addr;
- /*
- * See if the vioc has reset.
- */
- if (vp->v_fault != VXF_READY) {
- printf(" vxreset failed\n");
- splx(s);
- return;
- }
- /*
- * Send a LIDENT to the vioc and mess with carrier flags
- * on parallel printer ports.
- */
- vxinit(vx, 0);
- splx(s);
- }
-
- /*
- * Finish the reset on the vioc after an error (hopefully).
- *
- * Restore modem control, parameters and restart output.
- * Since the vioc can handle no more then 24 commands at a time
- * and we could generate as many as 48 commands, we must do this in
- * phases, issuing no more then 16 commands at a time.
- */
- vxfnreset(vx, cp)
- register int vx;
- register struct vxcmd *cp;
- {
- register struct vx_softc *vs;
- register struct vxdevice *vp;
- register struct tty *tp, *tp0;
- register int i;
- #ifdef notdef
- register int on;
- #endif
- extern int vxrestart();
- int s = spl8();
-
- vs = &vx_softc[vx];
- vrelease(vs, cp);
- vs->vs_state = VXS_READY;
-
- vp = vs->vs_addr;
- vp->v_vcid = 0;
-
- /*
- * Restore modem information and control.
- */
- tp0 = &vx_tty[vx*16];
- for (i = vs->vs_loport; i <= vs->vs_hiport; i++) {
- tp = tp0 + i;
- if (tp->t_state&(TS_ISOPEN|TS_WOPEN)) {
- tp->t_state &= ~TS_CARR_ON;
- vcmodem(tp->t_dev, VMOD_ON);
- if (tp->t_state&TS_CARR_ON)
- (void)(*linesw[tp->t_line].l_modem)(tp, 1);
- else if (tp->t_state & TS_ISOPEN)
- (void)(*linesw[tp->t_line].l_modem)(tp, 0);
- }
- #ifdef notdef
- /*
- * If carrier has changed while we were resetting,
- * take appropriate action.
- */
- on = vp->v_dcd & 1<<i;
- if (on && (tp->t_state&TS_CARR_ON) == 0)
- (void)(*linesw[tp->t_line].l_modem)(tp, 1);
- else if (!on && tp->t_state&TS_CARR_ON)
- (void)(*linesw[tp->t_line].l_modem)(tp, 0);
- #endif
- }
- vs->vs_state = VXS_RESET;
- timeout(vxrestart, (caddr_t)vx, hz);
- splx(s);
- }
-
- /*
- * Restore a particular aspect of the VIOC.
- */
- vxrestart(vx)
- int vx;
- {
- register struct tty *tp, *tp0;
- register struct vx_softc *vs;
- register int i, count;
- int s = spl8();
-
- count = vx >> 8;
- vx &= 0xff;
- vs = &vx_softc[vx];
- vs->vs_state = VXS_READY;
- tp0 = &vx_tty[vx*16];
- for (i = vs->vs_loport; i <= vs->vs_hiport; i++) {
- tp = tp0 + i;
- if (count != 0) {
- tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
- if (tp->t_state&(TS_ISOPEN|TS_WOPEN))
- vxstart(tp); /* restart pending output */
- } else {
- if (tp->t_state&(TS_WOPEN|TS_ISOPEN))
- vxcparam(tp, &tp->t_termios, 0);
- }
- }
- if (count == 0) {
- vs->vs_state = VXS_RESET;
- timeout(vxrestart, (caddr_t)(vx + 1*256), hz);
- } else
- printf(" vx reset done\n");
- splx(s);
- }
-
- vxreset(dev)
- dev_t dev;
- {
-
- vxstreset((int)VXUNIT(minor(dev))); /* completes asynchronously */
- }
-
- #ifdef VX_DEBUG
- vxfreset(vx)
- register int vx;
- {
- struct vba_device *vi;
-
- if ((unsigned)vx > NVX || (vi = vxinfo[vx]) == 0 || vi->ui_addr == 0)
- return (ENODEV);
- vx_softc[vx].vs_state = VXS_READY;
- vxstreset(vx);
- return (0); /* completes asynchronously */
- }
- #endif
-
- vcmodem(dev, flag)
- dev_t dev;
- {
- struct tty *tp;
- register struct vxcmd *cp;
- register struct vx_softc *vs;
- register struct vxdevice *kp;
- register port;
- int unit;
-
- unit = minor(dev);
- tp = &vx_tty[unit];
- vs = (struct vx_softc *)tp->t_addr;
- if (vs->vs_state != VXS_READY)
- return;
- cp = vobtain(vs);
- kp = vs->vs_addr;
-
- port = VXPORT(unit);
- /*
- * Issue MODEM command
- */
- cp->cmd = VXC_MDMCTL;
- if (flag == VMOD_ON) {
- if (vs->vs_softCAR & (1 << port)) {
- cp->par[0] = V_MANUAL | V_DTR_ON | V_RTS;
- kp->v_dcd |= (1 << port);
- } else
- cp->par[0] = V_AUTO | V_DTR_ON;
- } else
- cp->par[0] = V_DTR_OFF;
- cp->par[1] = port;
- (void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
- if ((kp->v_dcd | vs->vs_softCAR) & (1 << port) && flag == VMOD_ON)
- tp->t_state |= TS_CARR_ON;
- }
-
- /*
- * VCMINTR called when an unsolicited interrupt occurs signaling
- * some change of modem control state.
- */
- vcmintr(vx)
- register vx;
- {
- register struct vxdevice *kp;
- register struct tty *tp;
- register port;
- register struct vx_softc *vs;
-
- vs = &vx_softc[vx];
- kp = vs->vs_addr;
- port = kp->v_usdata[0] & 017;
- tp = &vx_tty[vx*16+port];
-
- if (kp->v_ustat & DCD_ON)
- (void)(*linesw[tp->t_line].l_modem)(tp, 1);
- else if ((kp->v_ustat & DCD_OFF) &&
- ((vs->vs_softCAR & (1 << port))) == 0 &&
- (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
- register struct vcmds *cp;
- register struct vxcmd *cmdp;
-
- /* clear all pending transmits */
- if (tp->t_state&(TS_BUSY|TS_FLUSH) &&
- vs->vs_vers == VXV_NEW) {
- int i, cmdfound = 0;
-
- cp = &vs->vs_cmds;
- for (i = cp->v_empty; i != cp->v_fill; ) {
- cmdp = (struct vxcmd *)((long *)cp->cmdbuf[i]-1);
- if ((cmdp->cmd == VXC_XMITDTA ||
- cmdp->cmd == VXC_XMITIMM) &&
- ((struct vxmit *)cmdp->par)->line == port) {
- cmdfound++;
- cmdp->cmd = VXC_FDTATOX;
- cmdp->par[1] = port;
- }
- if (++i >= VC_CMDBUFL)
- i = 0;
- }
- if (cmdfound)
- tp->t_state &= ~(TS_BUSY|TS_FLUSH);
- /* cmd is already in vioc, have to flush it */
- else {
- cmdp = vobtain(vs);
- cmdp->cmd = VXC_FDTATOX;
- cmdp->par[1] = port;
- (void) vcmd(vx, (caddr_t)&cmdp->cmd);
- }
- }
- } else if ((kp->v_ustat&BRK_CHR) && (tp->t_state&TS_ISOPEN)) {
- (*linesw[tp->t_line].l_rint)(TTY_FE, tp);
- return;
- }
- }
- #endif
-