V10/sys/io/vplot.c
/*
* Versatec model 122 matrix printer/plotter
* dma interface driver
*
*/
#include "sys/param.h"
#include "sys/conf.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/ubaddr.h"
#include "sys/vplot.h"
#include "sys/vplotcmd.h"
struct device {
short csr;
short buf;
};
#define ERROR 0100000
#define SPP 0020000
#define BTCNT 0010000
#define ADDR 0004000
#define PP 0002000
#define SWPBT 0001000
#define READY 0000200
#define IENABLE 0000100
#define XMEM 0000060
#define xmem(a) (((a) >> 12) & XMEM)
#define REMOTE 0000016
#define GO 0000001
#define MASK (SPP|PP|SWPBT|REMOTE)
#define RESET (06 << 1)
/*
* config glue
*/
int vplotopen(), vplotclose(), vplotwrite(), vplotioctl();
extern struct vplot vplot[];
extern struct ubaddr vplotaddr[];
extern int vplotcnt;
struct cdevsw vplotcdev =
cdinit(vplotopen, vplotclose, nodev, vplotwrite, vplotioctl);
#define VPLOTPRI (PZERO-1)
vplotopen(d, f)
{
register int dev;
register struct vplot *vp;
if((dev = minor(d)) >= vplotcnt) {
u.u_error = ENODEV;
return;
}
if((vp = &vplot[dev])->open) {
u.u_error = EBUSY;
return;
}
if((vp->addr = (struct device *)ubaddr(&vplotaddr[dev])) == 0
|| ubbadaddr(vplotaddr[dev].ubno, (caddr_t)vp->addr, sizeof(u_short))) {
printf("vplot%d absent\n", dev);
u.u_error = ENODEV;
return;
}
vp->open = 1;
vp->addr->csr = RESET;
if(vplotwait(vp)) {
u.u_error = ENXIO;
vplotclose(d);
return;
}
vp->addr->csr |= IENABLE;
vplottimo(vp);
if(u.u_error)
vplotclose(d);
}
vplotclose(d)
{
register struct vplot *vp = &vplot[minor(d)];
vp->open = 0;
vp->addr->csr = 0;
}
vplotstrategy(bp)
register struct buf *bp;
{
register struct vplot *vp = &vplot[minor(bp->b_dev)];
register ubm_t ubm;
register uaddr_t uaddr;
register int cc, e, s;
s = spl4();
(void) vplotwait(vp);
ubm = ubmbuf(vplotaddr[minor(bp->b_dev)].ubno, bp, UBDP|USLP);
uaddr = ubadbuf(vplotaddr[minor(bp->b_dev)].ubno, bp, ubm);
if(e = vplotwait(vp))
goto out;
if((cc = -(bp->b_bcount)) != 0) {
vp->addr->csr |= IENABLE | ADDR;
vp->addr->csr &= ~BTCNT;
vp->addr->buf = uaddr;
vp->addr->csr |= BTCNT;
vp->addr->buf = cc;
vp->addr->csr |= xmem(uaddr) | GO;
}
e = vplotwait(vp);
out:
(void) splx(s);
ubmfree(vplotaddr[minor(bp->b_dev)].ubno, ubm);
if(e)
bp->b_flags |= B_ERROR;
iodone(bp);
}
int vplotblock = 16384;
unsigned
minvplotph(bp)
struct buf *bp;
{
if(bp->b_bcount > vplotblock)
bp->b_bcount = vplotblock;
}
/*ARGSUSED*/
vplotwrite(d)
{
if(u.u_count == 0)
return;
physio(vplotstrategy, &vplot[minor(d)].buf, d, B_WRITE, minvplotph);
}
vplotwait(vp)
register struct vplot *vp;
{
register int e;
for(;;) {
if(vp->addr->csr & (ERROR|READY))
break;
if(tsleep((caddr_t)vp, VPLOTPRI, HZ) != TS_OK)
break;
}
if((vp->addr->csr & ERROR) == 0)
return 0;
/* Check for NXM - ERROR remains 1 if NOT NXM) */
vp->addr->csr &= ~ERROR;
if((e = (vp->addr->csr & ERROR)) == 0)
printf("vplot%d: NXM\n", vp - vplot);
return e;
}
/*ARGSUSED*/
vplotioctl(dev, cmd, addr, flag)
caddr_t addr;
{
register struct vplot *vp = &vplot[minor(dev)];
u_short csr;
int m;
switch(cmd) {
case VGETSTATE:
m = vp->addr->csr;
if(copyout((caddr_t)&m, addr, sizeof(m)))
u.u_error = EFAULT;
break;
case VSETSTATE:
if(copyin(addr, (caddr_t)&m, sizeof(m))) {
u.u_error = EFAULT;
return;
}
(void) spl4();
csr = (vp->addr->csr & ~MASK) | (m & MASK);
vp->addr->csr = csr;
if(vplotwait(vp))
u.u_error = EIO;
(void) spl0();
break;
default:
u.u_error = ENOTTY;
break;
}
}
vplottimo(vp)
register struct vplot *vp;
{
if(vp->open)
timeout(vplottimo, (caddr_t)vp, HZ/10);
vplot0int(vp - vplot);
}
vplot0int(d)
{
wakeup((caddr_t)&vplot[d]);
}