-/* vx.c 1.1 85/07/21 */
+/*
+ * 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 are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)vx.c 7.8 (Berkeley) %G%
+ */
#include "vx.h"
#if NVX > 0
/*
- * VIOC-X driver
+ * VIOC-X driver
*/
-
-#include "../h/param.h"
-#include "../h/ioctl.h"
-#include "../h/tty.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/map.h"
-#include "../machine/pte.h"
-#include "../h/buf.h"
-#include "../vba/vbavar.h"
-#include "../h/conf.h"
-#include "../h/file.h"
-#include "../h/uio.h"
-#include "../vba/vioc.h"
#ifdef VXPERF
-#include "../vba/scope.h"
-#endif VXPERF
-#include "vbsc.h"
-#if NVBSC > 0
-#include "../bsc/bscio.h"
-#include "../bsc/bsc.h"
-char bscport[NVXPORTS];
+#define DOSCOPE
#endif
-#ifdef BSC_DEBUG
-#include "../bsc/bscdebug.h"
-#endif
+#include "param.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "user.h"
+#include "map.h"
+#include "buf.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "vm.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "../tahoe/pte.h"
+
+#include "../tahoevba/vbavar.h"
+#include "../tahoevba/vbaparam.h"
+#include "../tahoevba/vxreg.h"
+#include "../tahoevba/scope.h"
-#ifdef VX_DEBUG
-long vxintr4 = 0;
-long vxdebug = 0;
-#include "../vba/vxdebug.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
-#define RSPquals 1
+/*
+ * Interrupt type bits passed to vinthandl().
+ */
+#define CMDquals 0 /* command completed interrupt */
+#define RSPquals 1 /* command response interrupt */
+#define UNSquals 2 /* unsolicited interrupt */
-struct vcx vcx[NVIOCX] ;
-struct tty vx_tty[NVXPORTS];
-extern struct vcmds v_cmds[];
-extern long reinit;
+#define VXUNIT(n) ((n) >> 4)
+#define VXPORT(n) ((n) & 0xf)
-int vxstart() ;
-int ttrstrt() ;
-caddr_t vtoph();
-struct vxcmd *vobtain() ;
-struct vxcmd *nextcmd() ;
+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.
- * (not tested and probably should be changed)
*/
int vxprobe(), vxattach(), vxrint();
-struct vba_device *vxinfo[NVIOCX];
+struct vba_device *vxinfo[NVX];
long vxstd[] = { 0 };
struct vba_driver vxdriver =
- { vxprobe, 0, vxattach, 0, vxstd, "vioc ", vxinfo };
-
-char vxtype[NVIOCX]; /* 0: viox-x/vioc-b; 1: vioc-bop */
-char vxbbno = -1;
-char vxbopno[NVIOCX]; /* BOP board no. if indicated by vxtype[] */
-extern vbrall();
-
-
-vxprobe(reg)
+ { 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;
- register struct vblok *vp = (struct vblok *)reg;
+ 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
-
- if(badaddr(vp, 1))
+#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->v_fault = 0 ;
- vp->v_vioc = V_BSY ;
- vp->v_hdwre = V_RESET ; /* reset interrupt */
-
+ }
+ 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);
- return ( vp->v_fault == VREADY);
+ 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(ui)
- register struct vba_device *ui;
+vxattach(vi)
+ register struct vba_device *vi;
{
- VIOCBAS[ui->ui_unit] = ui->ui_addr;
- vxinit(ui->ui_unit,1);
+ 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 vcx *xp; /* pointer to VIOC-X info/cmd buffer */
- register d; /* minor device number */
- register long jj;
-
-
- d = minor(dev); /* get minor device number */
- if (d >= NVXPORTS) /* validate minor device number */
- return ENXIO; /* set errno to indicate bad port # */
- tp = &vx_tty[d]; /* index the tty structure for port */
-
- xp = &vcx[d>>4]; /* index VIOC-X info/cmd area */
- d &= 017;
-
- /* If we did not find a board with the correct port number on
- it, or the entry for the VIOC-X had no ports on it, inform the
- caller that the port does not exist. */
- if(!( xp->v_loport <= d && d <= xp->v_hiport ) /* home? */
- || (xp->v_hiport - xp->v_loport)==0)
- return ENXIO; /* bad minor device number */
- tp->t_addr = (caddr_t)xp; /* store address of VIOC-X info */
- tp->t_oproc = vxstart; /* store address of startup routine */
- tp->t_dev = dev; /* store major/minor device numbers */
- d = spl8();
- tp->t_state |= TS_WOPEN; /* mark device as waiting for open */
- if ((tp->t_state&TS_ISOPEN) == 0) /* is device already open? */
- { /* no, open it */
- ttychars(tp); /* set default control chars */
- if (tp->t_ispeed == 0) /* if no default speeds set them */
- {
- tp->t_ispeed = SSPEED; /* default input baud */
- tp->t_ospeed = SSPEED; /* default output baud */
- tp->t_flags |= (ODDP|EVENP|ECHO); /* default modes */
+ 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(dev); /* set parameters for this port */
+ vxparam(tp, &tp->t_termios);
+ ttsetwater(tp);
}
- splx(d);
- /* ? if already open for exclusive use open fails unless caller is
- root. */
- if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
- return EBUSY; /* device is busy, sorry */
-
- /* wait for data carrier detect to go high */
- d = spl8();
- if( !vcmodem(dev,VMOD_ON) )
- while( (tp->t_state&TS_CARR_ON) == 0 )
- sleep(&tp->t_canq,TTIPRI);
- jj= (*linesw[tp->t_line].l_open)(dev,tp); /*let tty.c finish the open */
- splx(d); /* 1/2/85 : assures open complete */
- return (jj);
+ 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 = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0)) ||
+ (error = ttclosed(tp)))
+ 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)
-dev_t dev;
-int flag;
+ dev_t dev;
+ int flag;
{
register struct tty *tp;
- register d;
+ int unit, s, error = 0;
- d = minor(dev) & 0377;
- tp = &vx_tty[d];
- d = spl8();
+ unit = minor(dev);
+ tp = &vx_tty[unit];
+ s = spl8();
(*linesw[tp->t_line].l_close)(tp);
- if ((tp->t_state&TS_ISOPEN) && (tp->t_state&TS_HUPCLS))
- if( !vcmodem(dev,VMOD_OFF) )
- tp->t_state &= ~TS_CARR_ON;
+ 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)
- sleep( (caddr_t)&tp->t_state, TTOPRI ) ;
- ttyclose(tp); /* let tty.c finish the close */
- splx(d);
+ 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)
+vxread(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
- register struct tty *tp = &vx_tty[minor(dev) & 0377];
- return (*linesw[tp->t_line].l_read)(tp, 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)
+vxwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
- register struct tty *tp = &vx_tty[minor(dev) & 0377];
- return (*linesw[tp->t_line].l_write)(tp, uio);
+ register struct tty *tp = &vx_tty[minor(dev)];
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}
/*
* VIOCX unsolicited interrupt.
*/
-vxrint(n)
-register n; /* mux number */
+vxrint(vx)
+ register vx;
{
- register struct tty *tp;
- register struct vcx *xp;
- register short *sp;
- register struct vblok *kp;
- register int i, c;
- short *savsilo;
- struct silo {
- char data;
- char port;
- };
-
- kp = VBAS(n);
- xp = &vcx[n];
- switch(kp->v_uqual&037) {
+ 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:
- printf(" ERR NBR %x\n",kp->v_ustat);
- vpanic("vc: VC PROC ERR");
- vxstreset(n);
- return(0);
+ 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(n);
- return(1);
+ vcmintr(vx);
+ return;
case 4:
- return(1);
+ return;
default:
- printf(" ERR NBR %x\n",kp->v_uqual);
- vpanic("vc: VC UQUAL ERR");
- vxstreset(n);
- return(0);
+ printf("vx%d: vc uqual err, uqual %x\n", vx, addr->v_uqual);
+ vxstreset(vx);
+ return;
}
- if(xp->v_vers == V_NEW) {
- register short *aa ;
- aa = (short *)kp->v_usdata;
- sp = (short *)(*aa + (char *)kp) ;
- } else {
- c = kp->v_usdata[0] << 6;
- sp = (short *)((char *)kp + SILOBAS + c);
- }
-nextsilo:
- i = *(savsilo = sp);
- if (i == 0) return(1);
- if(xp->v_vers == V_NEW)
- if( i > xp->v_silosiz ) {
- printf("vx: %d exceeds silo size\n",i) ;
- i = xp->v_silosiz;
- }
- for(sp++;i > 0;i--,sp++) {
- c = ((struct silo *)sp)->port & 017;
- tp = &vx_tty[c+n*16];
- if(xp->v_loport > c || c > xp->v_hiport)
- continue; /* port out of bounds */
- if( (tp->t_state & TS_ISOPEN) == 0) {
+ 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 = ((struct silo *)sp)->data;
- switch(((struct silo *)sp)->port&(PERROR|FERROR)) {
- case PERROR:
- case PERROR|FERROR:
- if( (tp->t_flags&(EVENP|ODDP)) == EVENP
- || (tp->t_flags & (EVENP|ODDP)) == ODDP )
- continue;
- if(!(((struct silo *)sp)->port&FERROR))
- break;
- case FERROR:
- if(tp->t_flags & RAW) c = 0;
- else c = tp->t_intrc;
+ 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);
}
- *savsilo = 0;
- return(1);
+ *osp = 0;
}
/*
- * stty/gtty for VX
+ * Ioctl for VX.
*/
vxioctl(dev, cmd, data, flag)
-int dev; /* major, minor device numbers */
-int cmd; /* command */
-caddr_t data;
-int flag;
+ dev_t dev;
+ caddr_t data;
{
- register struct tty *tp;
- register error;
+ register struct tty *tp;
+ int error;
- tp = &vx_tty[minor(dev) & 0377];
+ tp = &vx_tty[minor(dev)];
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
- if (error == 0)
- return error;
- if((error = ttioctl(tp, cmd, data, flag)) >= 0)
- {
- if (cmd==TIOCSETP||cmd==TIOCSETN)
- vxparam(dev);
- return error;
- } else
- return ENOTTY;
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ return (ENOTTY);
}
-
-vxparam(dev)
-dev_t dev;
+vxparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
{
- vxcparam(dev, 1);
+
+ return (vxcparam(tp, t, 1));
}
/*
* Set parameters from open or stty into the VX hardware
* registers.
*/
-vxcparam(dev, wait)
-dev_t dev; /* major, minor device numbers */
-int wait; /* nonzero if we should wait for finish */
-{
- register struct tty *tp;
- register struct vcx *xp;
- register struct vxcmd *cp;
- register s;
-
- tp = &vx_tty[minor(dev)]; /* pointer to tty structure for port */
- xp = (struct vcx *)tp->t_addr; /* pointer to VIOCX info/cmd buffer */
- cp = vobtain(xp);
+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();
- cp->cmd = LPARAX; /* set command to "load parameters" */
- cp->par[1] = minor(dev)&017; /* port number */
-
- cp->par[2] = (tp->t_flags&RAW)? 0 : tp->t_startc; /* XON char */
- cp->par[3] = (tp->t_flags&RAW)? 0 : tp->t_stopc; /* XOFF char */
-
- if(tp->t_flags&(RAW|LITOUT) ||
- (tp->t_flags&(EVENP|ODDP)) == (EVENP|ODDP)) {
- cp->par[4] = 0xc0; /* 8 bits of data */
- cp->par[7] = 0; /* no parity */
- } else {
- cp->par[4] = 0x40; /* 7 bits of data */
- if((tp->t_flags&(EVENP|ODDP)) == ODDP)
- cp->par[7] = 1; /* odd parity */
- else if((tp->t_flags&(EVENP|ODDP)) == EVENP)
- cp->par[7] = 3; /* even parity */
+ /*
+ * 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[7] = 0; /* no parity */
+ 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);
}
- cp->par[5] = 0x4; /* 1 stop bit */
- cp->par[6] = tp->t_ospeed;
-
- if (vcmd(xp->v_nbr, &cp->cmd) && wait)
- sleep(cp,TTIPRI);
splx(s);
+ return (error);
}
/*
* For transmission, restart output to any active port.
* For all other commands, just clean up.
*/
-vxxint(n,cp)
-register int n; /* VIOC number */
-register struct vxcmd *cp; /* command structure */
-{
- register struct vxmit *vp, *pvp;
- register struct tty *tp;
- register struct vcx *xp;
- register struct tty *hp;
-
- xp = &vcx[n];
- cp = (struct vxcmd *)( (long *)cp - 1);
-#if NVBSC > 0
- switch(cp->cmd) {
- case MDMCTL1: case HUNTMD1: case LPARAX1:
- vrelease(xp, cp);
- wakeup(cp);
- return;
- }
-#endif
- switch(cp->cmd&0xff00) {
- case LIDENT: /* initialization complete */
- if (xp->v_state & V_RESETTING) {
- vxfnreset(n,cp);
- vinthandl(n,((V_BSY | RSPquals) << 8) | V_INTR);
+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 XMITDTA: case XMITIMM:
+
+ case VXC_XMITDTA:
+ case VXC_XMITIMM:
break;
- case LPARAX:
- wakeup(cp);
- default: /* MDMCTL or FDTATOX */
- vrelease(xp, cp);
- if (xp->v_state & V_RESETTING) {
- vinthandl(n,((V_BSY | RSPquals) << 8) | V_INTR);
- }
+
+ 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;
}
- for(vp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizvxmit);
- vp >= (struct vxmit *)cp->par;
- vp = (struct vxmit *) ((char *)vp - sizvxmit) )
- {
- tp = &vx_tty[(vp->line & 017)+n*16];
-/* cjk buffer bug */
-#if NVBSC > 0
- /* bsc change */
- if (tp->t_line == LDISP) {
- vrelease(xp, cp);
- bsctxd((vp->line & 017));
- return ;
- }
- /* End of bsc change */
-#endif
-/* cjk */
- pvp = vp;
+ 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) {
+ if (tp->t_state & TS_FLUSH) {
tp->t_state &= ~TS_FLUSH;
- wakeup( (caddr_t)&tp->t_state ) ;
- }
- else
+ wakeup((caddr_t)&tp->t_state);
+ } else
ndflush(&tp->t_outq, vp->bcount+1);
}
- xp->v_xmtcnt--;
- vrelease(xp,cp);
- if(xp->v_vers == V_NEW) {
- vp = pvp;
- xp->v_actport[(vp->line & 017) - xp->v_loport] |= 1 ;
- if(vxstart(tp) && (cp = nextcmd(xp)) != NULL)
- {
- xp->v_xmtcnt++;
- vcmd(n, &cp->cmd);
- return ;
+ 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);
}
- xp->v_actport[(vp->line & 017) - xp->v_loport] = 0 ;
- return ;
- }
- xp->v_actflg = 1;
- hp = &vx_tty[xp->v_hiport+n*16];
- for(tp = &vx_tty[xp->v_loport+n*16];tp <= hp;tp++)
- if(vxstart(tp) && (cp = nextcmd(xp)) != NULL)
- {
- xp->v_xmtcnt++;
- vcmd(n, &cp->cmd);
- }
- if( (cp = nextcmd(xp)) != NULL ) /* command to send ? */
- {
- xp->v_xmtcnt++;
- vcmd(n,&cp->cmd);
}
- xp->v_actflg = 0;
+ vs->vs_xmtcnt--;
}
/*
* Force out partial XMIT command after timeout
*/
-vxforce(xp)
-register struct vcx *xp;
+vxforce(vs)
+ register struct vx_softc *vs;
{
- register struct vxcmd *cp;
- register int s;
+ register struct vxcmd *cp;
+ int s;
s = spl8();
- if((cp = nextcmd(xp)) != NULL) {
- xp->v_xmtcnt++;
- vcmd(xp->v_nbr, &cp->cmd);
+ 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 struct tty *tp;
{
- register short nch;
- register struct vcx *xp;
- register char *outb;
- register full = 0;
- int k, s, port;
+ register short n;
+ register struct vx_softc *vs;
+ int s, port;
s = spl8();
- port = minor(tp->t_dev) & 017;
- xp = (struct vcx *)tp->t_addr;
- if (!(tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
- if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
+ 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);
tp->t_state &= ~TS_WCOLL;
}
}
- if(tp->t_outq.c_cc == 0) {
+ if (tp->t_outq.c_cc == 0) {
splx(s);
- return(0);
+ return;
}
-#ifdef VXPERF
- scope_out(3);
-#endif VXPERF
- if(!(tp->t_flags&(RAW|LITOUT)))
- full = 0200;
- if((nch = ndqb(&tp->t_outq, full)) == 0) {
- if(full) {
- nch = getc(&tp->t_outq);
- timeout(ttrstrt, (caddr_t)tp, (nch&0177) +6);
+ 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;
- full = 0;
+ n = 0;
}
- } else {
- outb = (char *)tp->t_outq.c_cf;
+ }
+ if (n) {
tp->t_state |= TS_BUSY;
- if(xp->v_vers == V_NEW)
- k = xp->v_actport[port - xp->v_loport] ;
- else
- k = xp->v_actflg ;
-
- full = vsetq(xp, port, outb, nch);
-
- if( (k&1) == 0 ) { /* not called from vxxint */
- if(full || xp->v_xmtcnt == 0) {
- outb = (char *)(&nextcmd(xp)->cmd);
- xp->v_xmtcnt++;
- vcmd(xp->v_nbr, outb );
- } else
- timeout(vxforce,xp,3);
- }
+ vsetq(vs, port, (char *)tp->t_outq.c_cf, n);
}
}
splx(s);
- return(full); /* indicate if max commands or not */
}
/*
* Stop output on a line.
*/
vxstop(tp)
-register struct tty *tp;
+ register struct tty *tp;
{
- register s;
+ int s;
s = spl8();
- if (tp->t_state & TS_BUSY) {
- if ((tp->t_state&TS_TTSTOP)==0) {
+ 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 which establishes interrupt vectors and logical
- * port numbers
+ * viocx to establish interrupt vectors and logical port numbers.
*/
-vxinit(i,wait)
-register int i;
-long wait;
-{
- register struct vcx *xp; /* ptr to VIOC-X info/cmd buffer */
- register struct vblok *kp; /* pointer to VIOC-X control block */
- register struct vxcmd *cp; /* pointer to a command buffer */
- register char *resp; /* pointer to response buffer */
- register int j;
- register struct vcmds *cpp;
- char type;
- register struct bsc *bp; /* bsc change */
- extern struct bsc bsc[];
-
-
- kp = VBAS(i); /* get base adr of cntl blok for VIOC */
-
- xp = &vcx[i]; /* index info/command buffers */
- cpp = &v_cmds[i];
- type = kp->v_ident;
- vxtype[i] = 0; /* Type is Viox-x */
- switch(type) {
- case VIOCX:
- {
- xp->v_vers = V_OLD ;
- /* set DCD for printer ports */
- for(j = 0;j < 16;j++)
- if (kp->v_portyp[j] == 4 )
- kp->v_dcd |= 1 << j ;
- }
- break ;
- case NWVIOCX:
- {
- xp->v_vers = V_NEW ;
- xp->v_silosiz = kp->v_maxsilo ;
- /* set DCD for printer ports */
- for(j = 0;j < 16;j++)
- if (kp->v_portyp[j] == 4 )
- kp->v_dcd |= 1 << j ;
- }
- break ;
- case PVIOCX:
- xp->v_vers = V_OLD ;
- break ;
- case NPVIOCX:
- xp->v_vers = V_NEW ;
- xp->v_silosiz = kp->v_maxsilo ;
- break ;
-#if NVBSC > 0
- case VIOCB: /* old f/w, Bisync board */
- printf("%X: %x%x OLD VIOC-B, ",
- (long)kp, (int)kp->v_ident,
- (int)kp->v_fault);
- xp->v_vers = V_OLD ;
- /* save device specific info */
- for(bp = &bsc[0]; bp <= &bsc[NBSC]; bp++)
- bp->b_devregs = (caddr_t)xp ;
- printf("%d BSC Ports initialized.\n",NBSC);
- break ;
-
- case NWVIOCB: /* new f/w, Bisync board */
- printf("%X: %x%x 16K VIOC-B, ",
- (long)kp, (int)kp->v_ident,
- (int)kp->v_fault);
- xp->v_vers = V_NEW ;
- xp->v_silosiz = kp->v_maxsilo ;
- /* save device specific info */
- for(bp = &bsc[0]; bp <= &bsc[NBSC]; bp++)
- bp->b_devregs = (caddr_t)xp ;
- printf("%d BSC Ports initialized.\n",NBSC);
- if(CBSIZE > kp->v_maxxmt)
- printf("vxinit: Warning CBSIZE > maxxmt\n") ;
- break ;
-#endif
- case VBOPID: /* VIOC-BOP */
- vxbbno++;
- vxtype[i] = 1;
- vxbopno[i] = vxbbno;
- printf("VIOC-BOP no. %d at %lx\n",vxbopno[i],VIOCBAS[i]);
+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:
- return ; /* Not a viocx type */
+ printf("vx%d: unknown type %x\n", vx, type);
+ unsup:
+ vxinfo[vx]->ui_alive = 0;
+ return;
}
- xp->v_nbr = -1; /* no number for it yet */
- xp->v_maxcmd = xp->v_vers == V_NEW ? 24 : 4;
-
- for(j=0; j<NVCXBUFS; j++) /* init all cmd buffers */
- {
- cp = &xp->vx_lst[j]; /* index a buffer */
- cp->c_fwd = &xp->vx_lst[j+1]; /* point to next buf */
+ 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];
}
- xp->vx_avail = &xp->vx_lst[0]; /* set idx to 1st free buf */
+ 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 */
- cp = vobtain(xp); /* grap the control block */
- cp->cmd = LIDENT; /* set command type */
- cp->par[0] = i * 4 + VCVECT; /* 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 */
- vcmd(i, &cp->cmd); /* initialize the VIOC-X */
+ /*
+ * 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;
- if (!wait) return;
- while(cp->cmd == LIDENT); /* wait for command completion */
+ 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 *)kp;
- resp += kp->v_rspoff & 0x3FFF;
-
- if(resp[0] != 0 && (resp[0]&0177) != 3) /* did init work? */
- {
- vrelease(xp,cp); /* init failed */
- return; /* try next VIOC-X */
+ resp = (char *)addr + (addr->v_rspoff&0x3fff);
+ if (resp[0] != 0 && (resp[0]&0177) != 3) {
+ vrelease(vs, cp); /* init failed */
+ return;
}
-
- xp->v_loport = cp->par[5]; /* save low port number */
- xp->v_hiport = cp->par[7];/* VIOC knows high port numbr */
- vrelease(xp,cp); /* done with this control block */
- xp->v_nbr = i; /* assign VIOC-X board number */
+ 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(xp)
-register struct vcx *xp;
+struct vxcmd *
+vobtain(vs)
+ register struct vx_softc *vs;
{
-
- register struct vxcmd *p;
- register s;
+ register struct vxcmd *p;
+ int s;
s = spl8();
- p = xp->vx_avail;
- if(p == (struct vxcmd *)0) {
+ p = vs->vs_avail;
+ if (p == (struct vxcmd *)0) {
#ifdef VX_DEBUG
- if (vxintr4 & VXNOBUF) vxintr4 &= ~VXNOBUF;
+ if (vxintr4&VXNOBUF)
+ vxintr4 &= ~VXNOBUF;
#endif
- vpanic("vx: no buffs");
- vxstreset(xp - vcx);
+ printf("vx%d: no buffers\n", vs->vs_nbr);
+ vxstreset(vs->vs_nbr);
splx(s);
- return(vobtain(xp));
+ return (vobtain(vs));
}
- xp->vx_avail = (xp->vx_avail)->c_fwd;
+ vs->vs_avail = p->c_fwd;
splx(s);
- return( (struct vxcmd *)p);
+ return ((struct vxcmd *)p);
}
/*
* Release a command buffer
*/
-vrelease(xp,cp)
-register struct vcx *xp;
-register struct vxcmd *cp;
+vrelease(vs, cp)
+ register struct vx_softc *vs;
+ register struct vxcmd *cp;
{
-
- register s;
+ int s;
#ifdef VX_DEBUG
- if (vxintr4 & VXNOBUF) return;
+ if (vxintr4&VXNOBUF)
+ return;
#endif
s = spl8();
- cp->c_fwd = xp->vx_avail;
- xp->vx_avail = cp;
+ 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);
+}
+
/*
- * vxcmd -
- *
+ * 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
*/
-struct vxcmd *
-nextcmd(xp)
-register struct vcx *xp;
+vcmd(vx, cmdad)
+ register int vx;
+ register caddr_t cmdad;
{
- register struct vxcmd *cp;
- register int s;
+ register struct vcmds *cp;
+ register struct vx_softc *vs = &vx_softc[vx];
+ int s;
s = spl8();
- cp = xp->vx_build;
- xp->vx_build = (struct vxcmd *)0;
+ /*
+ * 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(cp);
+ return (1);
}
/*
- * assemble transmits into a multiple command.
- * up to 8 transmits to 8 lines can be assembled together
+ * 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.
*/
-vsetq(xp ,d ,addr, cnt)
-register struct vcx *xp;
-caddr_t addr;
+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;
- register struct vxcmd *cp;
- register struct vxmit *mp;
- register char *p;
- register i;
+ 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);
+}
- cp = xp->vx_build;
- if(cp == (struct vxcmd *)0) {
- cp = vobtain(xp);
- xp->vx_build = cp;
- cp->cmd = XMITDTA;
+/*
+ * 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 {
- if((cp->cmd & 07) == 07) {
- vpanic("vx: vsetq overflow");
- vxstreset(xp->v_nbr);
- return(0);
+ 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);
}
- cp->cmd++;
+#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);
+}
- mp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizvxmit);
- mp->bcount = cnt-1;
+/*
+ * 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);
+}
- mp->line = d;
- if((xp->v_vers == V_NEW) && (cnt <= 6)) {
- cp->cmd = XMITIMM ;
- p = addr;
- /* bcopy(addr, &(char *)mp->ostream, cnt) ; */
- } else {
- addr = vtoph(0, (caddr_t)addr) ; /* should be a sys address */
- p = (char *)&addr;
- cnt = sizeof addr;
- /* mp->ostream = addr ; */
- }
- for(i=0; i<cnt; i++)
- mp->ostream[i] = *p++;
- if(xp->v_vers == V_NEW)
- return(1) ;
- else
- return((cp->cmd&07) == 7) ; /* Indicate if full */
+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