/* * Versatec matrix printer/plotter dma interface driver */ #include "sys/param.h" #include "sys/dir.h" #include "sys/user.h" #include "sys/buf.h" #include "sys/systm.h" #include "sys/ioctl.h" #include "sys/peri.h" #define VPPRI (PZERO+10) struct device { short plbcr, pbae, prbcr, pbaddr; short plcsr, plbuf, prcsr, prbuf; }; struct device *vp_addr[]; int vp_cnt; /* status bits */ #define ERROR 0100000 #define READY 0200 #define IENABLE 0100 #define FFCOM 020 #define RESET 02 #define SPP 01 /*states */ #define PRINT 0100 #define PLOT 0200 #define PPLOT 0400 vpopen(dev) register dev; { register struct vp *vp; register short *vpaddr; if (dev>=vp_cnt || (vp = &vp_vp[dev])->vp_buf) { u.u_error = ENXIO; return; } vpaddr = &(vp_addr[dev]->plcsr); *vpaddr = IENABLE|RESET; vp->vp_state = PRINT; if (vpready(dev)<0) { *vpaddr = 0; u.u_error = EIO; return; } *vpaddr = IENABLE|FFCOM; vp->vp_buf = geteblk(); vp->vp_offset = vp->vp_count = 0; } vpclose(dev) { register struct vp *vp; register short *vpaddr; vp = &vp_vp[dev]; vpaddr = &(vp_addr[dev]->plcsr); vpready(dev); *vpaddr = 0; if (vp->vp_buf) brelse(vp->vp_buf); vp->vp_buf = 0; } vpwrite(dev) register dev; { register struct vp *vp; register struct device *vpaddr; extern _sdata; vp = &vp_vp[dev]; vpaddr = vp_addr[dev]; if (vp->vp_count) { u.u_error = EIO; return; } while (u.u_count && u.u_error==0) { vp->vp_count = min(256,u.u_count); iomove(paddr(vp->vp_buf)+vp->vp_offset, vp->vp_count, B_WRITE); if (vpready(dev)<0) { u.u_error = EIO; vpaddr->plcsr = IENABLE|RESET; break; } vpaddr->pbaddr = (int)(paddr(vp->vp_buf)) - (int)(&_sdata) + vp->vp_offset; if (vp->vp_state&PLOT) vpaddr->plbcr = vp->vp_count; else vpaddr->prbcr = vp->vp_count; vp->vp_offset = 256 - vp->vp_offset; if (vp->vp_state&PPLOT) vp->vp_state = PLOT; } vp->vp_count = 0; } vpready(dev) { register struct vp *vp; register short *vpaddr; vp = &vp_vp[dev]; vpaddr = (vp->vp_state&PLOT)?&(vp_addr[dev]->plcsr): &(vp_addr[dev]->prcsr); spl4(); while ((*vpaddr&(READY|ERROR))==0) sleep(vp, VPPRI); spl0(); return(*vpaddr); } vpioctl(dev, cmd, arg, mode) { register struct vp *vp; register short *vpaddr; register bit; int tt[1]; vp = &vp_vp[dev]; vpaddr = &(vp_addr[dev]->plcsr); switch(cmd) { case IOCTYPE: u.u_rval1 = LIOC; break; case LIOCGETS: case TIOCGETP: u.u_rval1 = vp->vp_state; break; case TIOCSETP: if (copyin(arg, tt, sizeof(tt))) { u.u_error = EFAULT; return; } arg = tt[0]; case LIOCSETS: vpready(dev); vp->vp_state = arg; if (vp->vp_state&PPLOT) *vpaddr = IENABLE|SPP; else *vpaddr = IENABLE; for (bit=2; bit<IENABLE; bit<<=1) if (vp->vp_state&bit) { vpready(dev); *vpaddr |= bit; vp->vp_state &= ~bit; } break; default: u.u_error = EINVAL; } } vpintr(dev) { wakeup(&vp_vp[dev]); }