+ 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;
+ int s;
+
+ s = spl8();
+ vs = &vx_softc[vx];
+ /*
+ * 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 = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_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 = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_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 = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_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)
+ register int vx;
+{
+ register struct vcmds *cp;
+ register struct vxdevice *vp;
+ register short item;
+ register short *intr;
+
+ vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
+ if (vp->v_vioc&V_BSY)
+ return;
+ cp = &vx_softc[vx].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;
+ vx_softc[vx].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 vx;
+{
+ register struct vx_softc *vs;
+ register struct vxdevice *vp;
+ register struct vxcmd *cp;
+ register int j;
+ extern int vxinreset();
+ int s;
+
+ s = spl8() ;
+ vs = &vx_softc[vx];
+ if (vs->vs_state == VXS_RESET) { /* avoid recursion */
+ splx(s);
+ return;
+ }
+ vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_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, (unsigned)sizeof (*vs));
+
+ /*
+ * 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 = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
+ /*
+ * See if the vioc has reset.
+ */
+ if (vp->v_fault != VXF_READY) {
+ printf("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];
+ vs->vs_loport = cp->par[5];
+ vs->vs_hiport = cp->par[7];
+ vrelease(vs, cp);
+ vs->vs_nbr = vx; /* assign VIOC-X board number */
+ vs->vs_state = VXS_READY;
+
+ vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_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->t_dev, 0);
+ }
+ }
+ if (count == 0) {
+ vs->vs_state = VXS_RESET;
+ timeout(vxrestart, (caddr_t)(vx + 1*256), hz);
+ } else
+ printf("done\n");
+ splx(s);
+}
+
+vxreset(dev)
+ dev_t dev;
+{
+
+ vxstreset((int)VXUNIT(minor(dev))); /* completes asynchronously */
+}
+
+#ifdef notdef
+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 = (struct vxdevice *)((struct vba_device *)vxinfo[vs->vs_nbr])->ui_addr;
+
+ port = unit & 017;
+ /*
+ * 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;
+ else
+ cp->par[0] = V_AUTO | V_DTR_ON | V_RTS;
+ } else
+ cp->par[0] = V_DTR_OFF;
+ cp->par[1] = port;
+ (void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
+ if (vs->vs_softCAR & (1 << port))
+ kp->v_dcd |= (1 << port);
+ if ((kp->v_dcd | vs->vs_softCAR) & (1 << port) && flag == VMOD_ON)
+ tp->t_state |= TS_CARR_ON;
+}
+
+/*
+ * VCMINTR called when an unsolicited interrup 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;
+
+ kp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
+ port = kp->v_usdata[0] & 017;
+ tp = &vx_tty[vx*16+port];
+ vs = &vx_softc[vx];
+
+ 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)((tp->t_flags & RAW) ?
+ 0 : tp->t_intrc, tp);
+ return;
+ }