make bio and disk drivers not do spl0 so can call from panic without trap 2's
[unix-history] / usr / src / sys / vax / uba / va.c
index 9b8de04..e9d7c28 100644 (file)
@@ -1,6 +1,10 @@
-/*     va.c    3.5     %G%     */
+/*     va.c    4.11    81/11/18        */
 
 
-#ifdef ERNIE
+#include "va.h"
+#if NVA > 0
+/*
+ * Varian printer plotter
+ */
 #include "../h/param.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/param.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/systm.h"
 #include "../h/map.h"
 #include "../h/pte.h"
 #include "../h/systm.h"
 #include "../h/map.h"
 #include "../h/pte.h"
-#include "../h/uba.h"
+#include "../h/ubareg.h"
+#include "../h/ubavar.h"
 #include "../h/vcmd.h"
 
 #include "../h/vcmd.h"
 
-/*
- * Benson-Varian matrix printer/plotter.  Device "va", for "varian".
- * dma interface driver
- */
-int    vabdp = 1;      /* Used with ubasetup. */
-
-unsigned minvaph();    /* Maximum amount transferred by physio. */
+unsigned minvaph();
 
 #define        VAPRI   (PZERO-1)
 
 
 #define        VAPRI   (PZERO-1)
 
-struct varegs {        /* Unibus registers provided by va. */
-       unsigned short vabufaddr;       /* DMA buffer address. */
-       short vawcount;                 /* Negative of number of 16-bit
-                                          words to transfer by DMA. */
+struct vadevice {
+       u_short vaba;                   /* buffer address */
+       short   vawc;                   /* word count (2's complement) */
        union {
        union {
-               short vacsrword;        /* csr addressed as a word (for R). */
-               struct {
-                       char Vacsrlo;
-                       char Vacsrhi;   /* High byte (command bytes go here). */
-               } vacsrbytes;           /* csr addressed as bytes (for W). */
-       } vacsr;                        /* Control/Status Register (csr). */
-       short   vadata;
+               short   Vacsw;          /* control status as word */
+               struct {                /* control status as bytes */
+                       char Vacsl;
+                       char Vacsh;
+               } vacsr;
+       } vacs;
+       short   vadata;                 /* programmed i/o data buffer */
 };
 
 };
 
-#define        vacsrhi vacsr.vacsrbytes.Vacsrhi
-#define        vacsrlo vacsr.vacsrbytes.Vacsrlo
-#define        VAADDR  ((struct varegs *)(UBA0_DEV + 0164000))
-
-/* vacsr.vacsrword bits: */
-#define        ERROR           0100000         /* R    Some error has occurred */
-#define NPRTIMO                01000           /* R    DMA timeout error */
-#define NOTREADY       0400            /* R    Something besides NPRTIMO */
-#define DONE           0200            /* R    */
-#define        IENABLE         0100            /* R/W  Interrupt enable */
-#define        SUPPLIESLOW     04              /* R    */
-#define BOTOFFORM      02              /* R    */
-#define BYTEREVERSE    01              /* R/W  Reverse byte order in words */
-
-/* Command bytes sent to vacsrhi */
-#define VAPLOT         0340
-#define VAPRINT                0100
-#define VAPRINTPLOT    0160
-#define VAAUTOSTEP     0244
-/* The following commands are not used in this driver: */
-#define VANOAUTOSTEP   0045
-#define        VAFORMFEED      0263
-#define        VASLEW          0265
-#define        VASTEP          0064
-
-struct {
-       char    va_is_open;
-       char    va_busy;
-       int     va_state;       /* State: bits are commands in vcmd.h. */
-       int     va_wcount;
-       int     va_bufp;
-} vainfo;
-int    va_ubinfo;
-
-struct buf rvabuf;             /* Used by physio for a buffer. */
-
-vaopen()
+#define        vacsw   vacs.Vacsw
+#define        vacsh   vacs.vacsr.Vacsh
+#define        vacsl   vacs.vacsr.Vacsl
+
+/* vacsw bits */
+#define        VA_ERROR        0100000         /* some error has occurred */
+#define        VA_NPRTIMO      0001000         /* DMA timeout error */
+#define        VA_NOTREADY     0000400         /* something besides NPRTIMO */
+#define        VA_DONE         0000200
+#define        VA_IENABLE      0000100         /* interrupt enable */
+#define        VA_SUPPLIESLOW  0000004
+#define        VA_BOTOFFORM    0000002
+#define        VA_BYTEREVERSE  0000001         /* reverse byte order in words */
+
+/* vacsh command bytes */
+#define        VAPLOT          0000340
+#define        VAPRINT         0000100
+#define        VAPRINTPLOT     0000160
+#define        VAAUTOSTEP      0000244
+#define        VANOAUTOSTEP    0000045
+#define        VAFORMFEED      0000263
+#define        VASLEW          0000265
+#define        VASTEP          0000064
+
+struct va_softc {
+       char    sc_openf;
+       char    sc_busy;
+       int     sc_state;
+       int     sc_wc;
+       struct  buf *sc_bp;
+       int     sc_ubinfo;
+} va_softc[NVA];
+
+#define        VAUNIT(dev)     (minor(dev))
+
+struct buf rvabuf[NVA];
+
+int    vaprobe(), vaattach();
+struct uba_device *vadinfo[NVA];
+u_short        vastd[] = { 0764000, 0 };
+struct uba_driver vadriver =
+    { vaprobe, 0, vaattach, 0, vastd, "va", vadinfo };
+
+vaprobe(reg)
+       caddr_t reg;
 {
 {
+       register int br, cvec;          /* value-result */
+       register struct vadevice *vaaddr = (struct vadevice *)reg;
 
 
-       if (vainfo.va_is_open) {        /* Can't open if it's already open. */
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       vaintr(0);
+#endif
+       vaaddr->vacsl = VA_IENABLE;
+       vaaddr->vaba = 0;
+       vaaddr->vacsh = VAPLOT;
+       vaaddr->vacsl = 0;
+       vaaddr->vawc = -1;
+       DELAY(10000);
+       vaaddr->vacsl = 0;
+}
+
+/*ARGSUSED*/
+vaattach(ui)
+       struct uba_device *ui;
+{
+
+}
+
+vaopen(dev)
+       dev_t dev;
+{
+       register struct va_softc *sc;
+       register struct vadevice *vaaddr;
+       register struct uba_device *ui;
+
+       if (VAUNIT(dev) >= NVA || (sc = &va_softc[minor(dev)])->sc_openf ||
+           (ui = vadinfo[VAUNIT(dev)]) == 0 || ui->ui_alive == 0) {
                u.u_error = ENXIO;
                return;
        }
                u.u_error = ENXIO;
                return;
        }
-       vainfo.va_is_open = 1;          /* NOW it's open! */
-       VAADDR->vawcount = 0;           /* Clear residual errors */
-       vainfo.va_wcount = 0;           /* No DMA to do now. */
-       vainfo.va_state = 0;
-       VAADDR->vacsrlo = IENABLE;
-                                       /* Enable interrupts. */
-       vatimo();
-
-       vacmd(VPRINT);                  /* Start in print mode. */
+       vaaddr = (struct vadevice *)ui->ui_addr;
+       sc->sc_openf = 1;
+       vaaddr->vawc = 0;
+       sc->sc_wc = 0;
+       sc->sc_state = 0;
+       vaaddr->vacsl = VA_IENABLE;
+       vatimo(dev);
+       vacmd(dev, VPRINT);
        if (u.u_error)
        if (u.u_error)
-               vaclose();
+               vaclose(dev);
 }
 
 vastrategy(bp)
        register struct buf *bp;
 {
        register int e;
 }
 
 vastrategy(bp)
        register struct buf *bp;
 {
        register int e;
+       register struct va_softc *sc = &va_softc[VAUNIT(bp->b_dev)];
+       register struct uba_device *ui = vadinfo[VAUNIT(bp->b_dev)];
+       register struct vadevice *vaaddr = (struct vadevice *)ui->ui_addr;
 
        (void) spl4();
 
        (void) spl4();
-       while (vainfo.va_busy)          /* Wait till not busy. */
-               sleep((caddr_t)&vainfo, VAPRI);
-       vainfo.va_busy = 1;             /* Grab it. */
-       (void) spl0();
-
-       va_ubinfo = ubasetup(bp, vabdp);        /* Set up uba mapper. */
-       vainfo.va_bufp = va_ubinfo & 0x3ffff;
-
-       (void) spl4();
-       if (e = vaerror(DONE))
+       while (sc->sc_busy)
+               sleep((caddr_t)sc, VAPRI);
+       sc->sc_busy = 1;
+       sc->sc_bp = bp;
+       sc->sc_ubinfo = ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP);
+       if (e = vawait(bp->b_dev))
                goto brkout;
                goto brkout;
-       vainfo.va_wcount = -(bp->b_bcount/2);
-               /* va uses a word count, 
-                  so user had better supply an even number of bytes. */
-       vastart();
-       e = vaerror(DONE);      /* Wait for DMA to complete. */
-       vainfo.va_wcount = 0;   /* Reset state info. */
-       vainfo.va_bufp = 0;
-
-       /* After printing a line of characters, VPRINTPLOT mode essentially
-          reverts to VPLOT mode, plotting things until a new mode is set.
-          This change is indicated by sending a VAAUTOSTEP command to
-          the va.  We also change va_state to reflect this effective
-          mode change.
-        */
-       if (vainfo.va_state & VPRINTPLOT) {
-               vainfo.va_state = (vainfo.va_state & ~VPRINTPLOT) | VPLOT;
-               VAADDR->vacsrhi = VAAUTOSTEP;
-               e |= vaerror(DONE);
+       sc->sc_wc = -(bp->b_bcount/2);
+       vastart(bp->b_dev);
+       e = vawait(bp->b_dev);
+       sc->sc_wc = 0;
+       if (sc->sc_state & VPRINTPLOT) {
+               sc->sc_state = (sc->sc_state & ~VPRINTPLOT) | VPLOT;
+               vaaddr->vacsh = VAAUTOSTEP;
+               e |= vawait(bp->b_dev);
        }
        (void) spl0();
 brkout:
        }
        (void) spl0();
 brkout:
-       ubafree(va_ubinfo), va_ubinfo = 0;
-       vainfo.va_busy = 0;
+       ubarelse(ui->ui_ubanum, &sc->sc_ubinfo);
+       sc->sc_bp = 0;
+       sc->sc_busy = 0;
        iodone(bp);
        if (e)
                u.u_error = EIO;
        iodone(bp);
        if (e)
                u.u_error = EIO;
-       wakeup((caddr_t)&vainfo);
+       wakeup((caddr_t)sc);
 }
 
 int    vablock = 16384;
 
 unsigned
 minvaph(bp)
 }
 
 int    vablock = 16384;
 
 unsigned
 minvaph(bp)
-struct buf *bp;
+       struct buf *bp;
 {
 {
+
        if (bp->b_bcount > vablock)
                bp->b_bcount = vablock;
 }
 
 /*ARGSUSED*/
 vawrite(dev)
        if (bp->b_bcount > vablock)
                bp->b_bcount = vablock;
 }
 
 /*ARGSUSED*/
 vawrite(dev)
+       dev_t dev;
 {
 {
-       physio(vastrategy, &rvabuf, dev, B_WRITE, minvaph);
+
+       physio(vastrategy, &rvabuf[VAUNIT(dev)], dev, B_WRITE, minvaph);
 }
 
 }
 
-/*
- * Vaerror waits until bit or ERROR gets set, then returns non-zero if
- * if it was ERROR that was set.
- */
-vaerror(bit)
+vawait(dev)
+       dev_t dev;
 {
 {
+       register struct vadevice *vaaddr =
+           (struct vadevice *)vadinfo[VAUNIT(dev)]->ui_addr;
        register int e;
 
        register int e;
 
-       while ((e = VAADDR->vacsr.vacsrword & (bit|ERROR)) == 0)
-               sleep((caddr_t)&vainfo, VAPRI);
-       return (e & ERROR);
+       while (((e = vaaddr->vacsw) & (VA_DONE|VA_ERROR)) == 0)
+               sleep((caddr_t)&va_softc[VAUNIT(dev)], VAPRI);
+       if (e & VA_NPRTIMO)
+               printf("va%d: npr timeout\n", VAUNIT(dev));
+       return (e & VA_ERROR);
 }
 
 }
 
-/* vastart starts up the DMA by setting the buffer pointer and the word count. */
-vastart()
+vastart(dev)
+       dev_t;
 {
 {
-       if (vainfo.va_wcount) {
-               VAADDR->vabufaddr = vainfo.va_bufp;
-               VAADDR->vawcount = vainfo.va_wcount;
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+       register struct vadevice *vaaddr =
+           (struct vadevice *)vadinfo[VAUNIT(dev)]->ui_addr;
+
+       if (sc->sc_wc == 0)
                return;
                return;
-       }
+       vaaddr->vaba = sc->sc_ubinfo;
+       vaaddr->vacsl = (sc->sc_ubinfo >> 12) & 0x30;
+       vaaddr->vawc = sc->sc_wc;
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
@@ -181,11 +214,12 @@ vaioctl(dev, cmd, addr, flag)
        register caddr_t addr;
 {
        register int vcmd;
        register caddr_t addr;
 {
        register int vcmd;
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
 
        switch (cmd) {
 
        case VGETSTATE:
 
        switch (cmd) {
 
        case VGETSTATE:
-               (void) suword(addr, vainfo.va_state);
+               (void) suword(addr, sc->sc_state);
                return;
 
        case VSETSTATE:
                return;
 
        case VSETSTATE:
@@ -194,71 +228,115 @@ vaioctl(dev, cmd, addr, flag)
                        u.u_error = EFAULT;
                        return;
                }
                        u.u_error = EFAULT;
                        return;
                }
-               vacmd(vcmd);
+               vacmd(dev, vcmd);
                return;
 
        default:
                return;
 
        default:
-               u.u_error = ENOTTY;     /* Not a legal ioctl cmd. */
+               u.u_error = ENOTTY;
                return;
        }
 }
 
                return;
        }
 }
 
-/* vacmd sends a command code to the va, and waits for it to complete.
-   If an error occurs, u.u_error is set to EIO.
-   vacmd also updates vainfo.va_state.
- */
-
-vacmd(vcmd)
+vacmd(dev, vcmd)
+       dev_t dev;
+       int vcmd;
 {
 {
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+       register struct vadevice *vaaddr =
+           (struct vadevice *)vadinfo[VAUNIT(dev)]->ui_addr;
+
        (void) spl4();
        (void) spl4();
-       (void) vaerror(DONE);   /* Wait for va to be ready. */
+       (void) vawait(dev);
        switch (vcmd) {
 
        case VPLOT:
                /* Must turn on plot AND autostep modes. */
        switch (vcmd) {
 
        case VPLOT:
                /* Must turn on plot AND autostep modes. */
-               VAADDR->vacsrhi = VAPLOT;
-               if (vaerror(DONE))
+               vaaddr->vacsh = VAPLOT;
+               if (vawait(dev))
                        u.u_error = EIO;
                        u.u_error = EIO;
-               VAADDR->vacsrhi = VAAUTOSTEP;
+               vaaddr->vacsh = VAAUTOSTEP;
                break;
 
        case VPRINT:
                break;
 
        case VPRINT:
-               VAADDR->vacsrhi = VAPRINT;
+               vaaddr->vacsh = VAPRINT;
                break;
 
        case VPRINTPLOT:
                break;
 
        case VPRINTPLOT:
-               VAADDR->vacsrhi = VAPRINTPLOT;
+               vaaddr->vacsh = VAPRINTPLOT;
                break;
        }
                break;
        }
-       vainfo.va_state =
-               (vainfo.va_state & ~(VPLOT | VPRINT | VPRINTPLOT)) | vcmd;
-
-       if (vaerror(DONE))      /* Wait for command to complete. */
+       sc->sc_state = (sc->sc_state & ~(VPLOT|VPRINT|VPRINTPLOT)) | vcmd;
+       if (vawait(dev))
                u.u_error = EIO;
        (void) spl0();
 }
 
                u.u_error = EIO;
        (void) spl0();
 }
 
-vatimo()
+vatimo(dev)
+       dev_t dev;
 {
 {
-       if (vainfo.va_is_open)
-               timeout(vatimo, (caddr_t)0, HZ/10);
-       vaintr(0);
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+
+       if (sc->sc_openf)
+               timeout(vatimo, (caddr_t)dev, hz/10);
+       vaintr(dev);
 }
 
 /*ARGSUSED*/
 vaintr(dev)
 }
 
 /*ARGSUSED*/
 vaintr(dev)
+       dev_t dev;
 {
 {
-       wakeup((caddr_t)&vainfo);
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+
+       wakeup((caddr_t)sc);
 }
 
 }
 
-vaclose()
+vaclose(dev)
+       dev_t dev;
 {
 {
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+       register struct vadevice *vaaddr =
+           (struct vadevice *)vadinfo[VAUNIT(dev)]->ui_addr;
+
+       sc->sc_openf = 0;
+       sc->sc_busy = 0;
+       sc->sc_state = 0;
+       sc->sc_ubinfo = 0;
+       vaaddr->vacsl = 0;
+}
 
 
-       vainfo.va_is_open = 0;
-       vainfo.va_busy = 0;
-       vainfo.va_state = 0;
-       vainfo.va_wcount = 0;
-       vainfo.va_bufp = 0;
-       VAADDR->vacsrlo = 0;
+vareset(uban)
+       int uban;
+{
+       register int va11;
+       register struct uba_device *ui;
+       register struct va_softc *sc = va_softc;
+       register struct vadevice *vaaddr;
+
+       for (va11 = 0; va11 < NVA; va11++, sc++) {
+               if ((ui = vadinfo[va11]) == 0 || ui->ui_alive == 0 ||
+                   ui->ui_ubanum != uban || sc->sc_openf == 0)
+                       continue;
+               printf(" va%d", va11);
+               vaaddr = (struct vadevice *)ui->ui_addr;
+               vaaddr->vacsl = VA_IENABLE;
+               if (sc->sc_state & VPLOT) {
+                       vaaddr->vacsh = VAPLOT;
+                       DELAY(10000);
+                       vaaddr->vacsh = VAAUTOSTEP;
+               } else if (sc->sc_state & VPRINTPLOT)
+                       vaaddr->vacsh = VPRINTPLOT;
+               else
+                       vaaddr->vacsh = VAPRINTPLOT;
+               DELAY(10000);
+               if (sc->sc_busy == 0)
+                       continue;
+               if (sc->sc_ubinfo) {
+                       printf("<%d>", (sc->sc_ubinfo>>28)&0xf);
+                       ubarelse(ui->ui_ubanum, &sc->sc_ubinfo);
+               }
+               sc->sc_ubinfo = ubasetup(ui->ui_ubanum, sc->sc_bp, UBA_NEEDBDP);
+               sc->sc_wc = -(sc->sc_bp->b_bcount/2);
+               vastart(sc->sc_bp->b_dev);
+       }
 }
 #endif
 }
 #endif