SysIII/usr/src/uts/vax/io/vpmt.c
/*Version 2*/
#include "sys/param.h"
#include "sys/tty.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/file.h"
#include "sys/vpm.h"
#include "sys/vpmd.h"
#include "sys/ioctl.h"
#define BISYNC 6 /*BISYNC interpreter*/
#define VPMTS 4 /*Number of Virtual Protocol Machines*/
#define XBQMAX 2 /*Max xmit buffers in xmit queue*/
#define BUFDES (XBQMAX + 2)*VPMTS /*Number of buffer descriptors*/
#define BUFSIZE 512 /*Buffer size*/
#define NOARG 0 /*Null argument*/
#define VPMPRI (PZERO+5)
/*vpm state bits*/
#define OPEN 01
#define WCLOSE 02
#define VPMERR 04
#define XOPEN 010
int vpm_cnt;
/*Buffer discriptors*/
struct vpmbd vpmbd[BUFDES];
/*Per vmp structure*/
struct vpmt {
struct clist vt_rcvq;
struct vpmbd *vt_rbc;
short vt_state; /*Status info*/
} vpmt[VPMTS];
extern struct vpmbd *vpmdeq();
extern struct buf *getablk();
extern struct buf *geteblk();
vpmopen(dev, flag)
{
register struct vpmt *vp;
register int ec;
extern struct vpmbd *vpmbget();
extern vpmtrint();
if (TDEV(dev) >= vpm_cnt) {
u.u_error = ENXIO;
return;
}
if (((vp = &vpmt[TDEV(dev)])->vt_state&OPEN) == 0) {
if (ec = vpmstart(dev, BISYNC, vpmtrint)) {
vpmsave('p', dev, ec, 0);
u.u_error = ec;
return;
}
if ((flag&FREAD) && (flag&FWRITE))
vp->vt_state |= (XOPEN|OPEN);
else
vp->vt_state |= OPEN;
vpmemptq(dev, vpmbget(dev));
vpmemptq(dev, vpmbget(dev));
} else {
if ((vp->vt_state&XOPEN) || ((flag&FREAD) && (flag&FWRITE))) {
u.u_error = EBUSY;
return;
}
}
vpmsave('o', dev, vp->vt_state, 0);
}
vpmclose(dev)
{
struct vpmt *vp;
struct vpmbd *bdp;
vp = &vpmt[TDEV(dev)];
vp->vt_state |= WCLOSE;
vpmstop(dev);
while(vpmdeq(&vp->vt_rcvq));
for(bdp = &vpmbd[0];bdp < &vpmbd[BUFDES];bdp++)
if (bdp->d_vpmtdev == TDEV(dev))
vpmbrtn(bdp);
vpmsave('c', dev, vp->vt_state, 0);
vp->vt_state = 0;
vp->vt_rbc = 0;
if (vp->vt_state&VPMERR)
u.u_error = EIO;
}
vpmwrite(dev)
{
register struct vpmt *vp;
register struct vpmbd *dp;
register ct;
vp = &vpmt[TDEV(dev)];
if (vp->vt_state&VPMERR) {
u.u_error = EIO;
return;
}
while(u.u_count) {
spl5();
while(vpmxmtq(dev, 0) >= XBQMAX && (vp->vt_state&VPMERR) == 0)
sleep((caddr_t)&vp->vt_state, VPMPRI);
spl0();
if (vp->vt_state&VPMERR) {
u.u_error = EIO;
return;
}
dp = vpmbget(dev);
ct = min(u.u_count, BUFSIZE);
MOVE(paddr(dp->d_buf), ct, B_WRITE);
dp->d_ct = ct;
vpmsave('w', dev, ct, dp);
vpmxmtq(dev, dp);
}
}
vpmread(dev)
{
register struct vpmt *vp;
register struct vpmbd *dp;
register cnt;
vp = &vpmt[TDEV(dev)];
if (vp->vt_state&VPMERR) {
u.u_error = EIO;
return;
}
if (vp->vt_rbc == 0) {
spl5();
while((vp->vt_rbc = vpmdeq(&vp->vt_rcvq)) == 0 && (vp->vt_state&VPMERR) == 0)
sleep((caddr_t)&vp->vt_rcvq, VPMPRI);
spl0();
if (vp->vt_state&VPMERR) {
u.u_error = EIO;
return;
}
}
dp = vp->vt_rbc;
cnt = dp->d_ct - dp->d_bos;
cnt = min(cnt, u.u_count);
MOVE(paddr(dp->d_buf) + dp->d_bos, cnt, B_READ);
vpmsave('r', dev, cnt, dp->d_bos);
if ((dp->d_bos += cnt) == (dp->d_ct)) {
vp->vt_rbc = 0;
dp->d_ct = BUFSIZE;
dp->d_bos = 0;
vpmemptq(dev, dp);
}
}
vpmioctl(dev, cmd, arg, mode)
{
register struct vpmt *vp;
char cmdar[4], *cp;
extern char *vpmrpt(), *vpmerrs();
vp = &vpmt[TDEV(dev)];
switch(cmd) {
case VPMCMD:
copyin(arg, cmdar, sizeof(cmdar));
vpmcmd(dev, cmdar);
return;
case VPMERRS:
cp = vpmerrs(dev, 8);
copyout(cp, arg, 8);
return;
case VPMRPT:
if (cp = vpmrpt(dev)) {
copyout(cp, arg, 4);
u.u_rval1 = 1;
}
return;
default:
u.u_error = EINVAL;
return;
}
}
vpmtrint(dev, type, bdp)
{
register struct vpmt *vp;
vp = &vpmt[TDEV(dev)];
switch(type) {
case RRTNXBUF:
vpmbrtn(bdp);
wakeup((caddr_t)&vp->vt_state);
break;
case RRTNRBUF:
vpmenq(bdp, &vp->vt_rcvq);
wakeup((caddr_t)&vp->vt_rcvq);
break;
case RRTNEBUF:
vpmbrtn(bdp);
break;
case ERRTERM:
vp->vt_state |= VPMERR;
wakeup((caddr_t)&vp->vt_rcvq);
wakeup((caddr_t)&vp->vt_state);
break;
}
}
struct vpmbd *
vpmbget(dev)
{
register struct vpmbd *dp;
paddr_t addr;
for(dp = &vpmbd[0];dp < &vpmbd[BUFDES];dp++)
if (dp->d_buf == 0) {
dp->d_buf = (struct buf *)1;
break;
}
if (dp < &vpmbd[BUFDES]) {
dp->d_buf = GETBLK;
addr = ubmaddr(dp->d_buf, 0);
dp->d_adres = loword(addr);
dp->d_hbits = hiword(addr);
dp->d_bos = 0;
dp->d_ct = BUFSIZE;
dp->d_vpmtdev = TDEV(dev);
return(dp);
}
return(0);
}
vpmbrtn(dp)
struct vpmbd *dp;
{
if (dp->d_buf != NULL) {
brelse(dp->d_buf);
dp->d_buf = NULL;
}
}