Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

304 lines
6.3 KiB
C

#ifndef lint
static char sccsid[] = "@(#)vp.c 1.1 92/07/30 Copyr 1986 Sun Micro";
#endif
/*
* Copyright (c) 1986 by Sun Microsystems, Inc.
*/
/*
* Versatec matrix printer/plotter
* dma interface driver for Ikon 10071-5 Multibus/Versatec interface
*/
#include "vp.h"
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/map.h>
#include <sys/ioctl.h>
#include <sys/vcmd.h>
#include <sys/uio.h>
#include <machine/psl.h>
#include <machine/mmu.h>
#include <sundev/vpreg.h>
#include <sundev/mbvar.h>
#define VPPRI (PZERO-1)
struct vp_softc {
int sc_state;
struct buf *sc_bp;
int sc_mbinfo;
} vp_softc[NVP];
#define VPSC_BUSY 0400000
/* sc_state bits - passed in VGETSTATE and VSETSTATE ioctls */
#define VPSC_MODE 0000700
#define VPSC_SPP 0000400
#define VPSC_PLOT 0000200
#define VPSC_PRINT 0000100
#define VPSC_CMNDS 0000076
#define VPSC_OPEN 0000001
#define VPUNIT(dev) (minor(dev))
struct buf rvpbuf[NVP];
int vpprobe(), vpintr();
struct mb_device *vpdinfo[NVP];
struct mb_driver vpdriver = {
vpprobe, 0, 0, 0, 0, vpintr,
sizeof (struct vpdevice), "vp", vpdinfo, 0, 0, MDR_DMA,
};
vpprobe(reg)
caddr_t reg;
{
register struct vpdevice *vpaddr = (struct vpdevice *)reg;
register int x;
x = peek((short *)&vpaddr->vp_status);
if (x == -1 || (x & VP_IS8237) == 0)
return (0);
if (poke((short *)&vpaddr->vp_cmd, VP_RESET))
return (0);
/* initialize 8259 so we don't get constant interrupts */
vpaddr->vp_icad0 = 0x12; /* ICW1, edge-trigger */
DELAY(1);
vpaddr->vp_icad1 = 0xFF; /* ICW2 - don't care (non-zero) */
DELAY(1);
vpaddr->vp_icad1 = 0xFE; /* IR0 - interrupt on DRDY edge */
/* reset 8237 */
vpaddr->vp_clear = 1;
return (sizeof (struct vpdevice));
}
vpopen(dev)
dev_t dev;
{
register struct vp_softc *sc;
register struct mb_device *md;
register int s;
static int vpwatch = 0;
if (VPUNIT(dev) >= NVP ||
((sc = &vp_softc[minor(dev)])->sc_state&VPSC_OPEN) ||
(md = vpdinfo[VPUNIT(dev)]) == 0 || md->md_alive == 0)
return (ENXIO);
if (!vpwatch) {
vpwatch = 1;
vptimo();
}
sc->sc_state = VPSC_OPEN|VPSC_PRINT | VPC_CLRCOM|VPC_RESET;
while (sc->sc_state & VPSC_CMNDS) {
s = splx(pritospl(md->md_intpri));
if (vpwait(dev)) {
vpclose(dev);
(void) splx(s);
return (EIO);
}
vpcmd(dev);
(void) splx(s);
}
return (0);
}
vpclose(dev)
dev_t dev;
{
register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
sc->sc_state = 0;
}
vpstrategy(bp)
register struct buf *bp;
{
register struct vp_softc *sc = &vp_softc[VPUNIT(bp->b_dev)];
register struct mb_device *md = vpdinfo[VPUNIT(bp->b_dev)];
register struct vpdevice *vpaddr = (struct vpdevice *)md->md_addr;
int s;
int pa, wc;
if (((int)bp->b_un.b_addr & 1) || bp->b_bcount < 2) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
s = splx(pritospl(md->md_intpri));
while (sc->sc_bp != NULL) /* single thread */
(void) sleep((caddr_t)sc, VPPRI);
sc->sc_bp = bp;
(void) vpwait(bp->b_dev);
sc->sc_mbinfo = mbsetup(md->md_hd, bp, 0);
vpaddr->vp_clear = 1;
pa = MBI_ADDR(sc->sc_mbinfo);
vpaddr->vp_hiaddr = (pa >> 16) & 0xF;
pa = (pa >> 1) & 0x7FFF;
wc = (bp->b_bcount >> 1) - 1;
bp->b_resid = 0;
vpaddr->vp_addr = pa & 0xFF;
vpaddr->vp_addr = pa >> 8;
vpaddr->vp_wc = wc & 0xFF;
vpaddr->vp_wc = wc >> 8;
vpaddr->vp_mode = VP_DMAMODE;
vpaddr->vp_clrmask = 1;
sc->sc_state |= VPSC_BUSY;
(void) splx(s);
}
/*ARGSUSED*/
vpwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
if (VPUNIT(dev) >= NVP)
return (ENXIO);
return (physio(vpstrategy, &rvpbuf[VPUNIT(dev)], dev, B_WRITE,
minphys, uio));
}
vpwait(dev)
dev_t dev;
{
register struct vpdevice *vpaddr =
(struct vpdevice *)vpdinfo[VPUNIT(dev)]->md_addr;
register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
for (;;) {
if ((sc->sc_state & VPSC_BUSY) == 0 &&
vpaddr->vp_status & VP_DRDY)
break;
(void) sleep((caddr_t)sc, VPPRI);
}
return (0); /* NO ERRORS YET */
}
struct pair {
char soft; /* software bit */
char hard; /* hardware bit */
} vpbits[] = {
VPC_RESET, VP_RESET,
VPC_CLRCOM, VP_CLEAR,
VPC_EOTCOM, VP_EOT,
VPC_FFCOM, VP_FF,
VPC_TERMCOM, VP_TERM,
0, 0,
};
vpcmd(dev)
dev_t;
{
register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
register struct vpdevice *vpaddr =
(struct vpdevice *)vpdinfo[VPUNIT(dev)]->md_addr;
register struct pair *bit;
for (bit = vpbits; bit->soft != 0; bit++) {
if (sc->sc_state & bit->soft) {
vpaddr->vp_cmd = bit->hard;
sc->sc_state &= ~bit->soft;
DELAY(100); /* time for DRDY to drop */
return;
}
}
}
/*ARGSUSED*/
vpioctl(dev, cmd, data, flag)
dev_t dev;
int cmd;
caddr_t data;
int flag;
{
register int m;
register struct mb_device *md = vpdinfo[VPUNIT(dev)];
register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
register struct vpdevice *vpaddr = (struct vpdevice *)md->md_addr;
int s;
switch (cmd) {
case VGETSTATE:
*(int *)data = sc->sc_state;
break;
case VSETSTATE:
m = *(int *)data;
sc->sc_state =
(sc->sc_state & ~VPSC_MODE) | (m&(VPSC_MODE|VPSC_CMNDS));
break;
default:
return (ENOTTY);
}
s = splx(pritospl(md->md_intpri));
(void) vpwait(dev);
if (sc->sc_state&VPSC_SPP)
vpaddr->vp_status = VP_SPP|VP_PLOT;
else if (sc->sc_state&VPSC_PLOT)
vpaddr->vp_status = VP_PLOT;
else
vpaddr->vp_status = 0;
while (sc->sc_state & VPSC_CMNDS) {
(void) vpwait(dev);
vpcmd(dev);
}
(void) splx(s);
return (0);
}
vpintr()
{
register int dev;
register struct mb_device *md;
register struct vpdevice *vpaddr;
register struct vp_softc *sc;
register int found = 0;
for (dev = 0; dev < NVP; dev++) {
if ((md = vpdinfo[dev]) == NULL)
continue;
vpaddr = (struct vpdevice *)md->md_addr;
vpaddr->vp_icad0 = VP_ICPOLL;
DELAY(1);
if (vpaddr->vp_icad0 & 0x80) {
found = 1;
DELAY(1);
vpaddr->vp_icad0 = VP_ICEOI;
}
sc = &vp_softc[dev];
if ((sc->sc_state&VPSC_BUSY) && (vpaddr->vp_status & VP_DRDY)) {
sc->sc_state &= ~VPSC_BUSY;
if (sc->sc_state & VPSC_SPP) {
sc->sc_state &= ~VPSC_SPP;
sc->sc_state |= VPSC_PLOT;
vpaddr->vp_status = VP_PLOT;
}
iodone(sc->sc_bp);
sc->sc_bp = NULL;
mbrelse(md->md_hd, &sc->sc_mbinfo);
}
wakeup((caddr_t)sc);
}
return (found);
}
vptimo()
{
int s;
register struct mb_device *md = vpdinfo[0];
s = splx(pritospl(md->md_intpri));
(void) vpintr();
(void) splx(s);
timeout(vptimo, (caddr_t)0, hz);
}