update from Mike Hibler
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Mon, 5 Nov 1990 11:38:28 +0000 (03:38 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Mon, 5 Nov 1990 11:38:28 +0000 (03:38 -0800)
SCCS-vsn: sys/hp300/dev/nhpib.c 7.2
SCCS-vsn: sys/hp300/dev/ppi.c 7.2

usr/src/sys/hp300/dev/nhpib.c
usr/src/sys/hp300/dev/ppi.c

index 8bf6547..c437c29 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nhpib.c     7.1 (Berkeley) %G%
+ *     @(#)nhpib.c     7.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -78,85 +78,98 @@ nhpibifc(hd)
        hd->hpib_acr = AUX_SSRE;
 }
 
        hd->hpib_acr = AUX_SSRE;
 }
 
-nhpibsend(unit, slave, sec, addr, cnt)
+nhpibsend(unit, slave, sec, addr, origcnt)
        register char *addr;
        register char *addr;
-       register int cnt;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
-       register int origcnt = cnt;
+       register int cnt = origcnt;
 
        hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
        hd->hpib_acr = AUX_TCA;
        hd->hpib_data = C_UNL;
 
        hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
        hd->hpib_acr = AUX_TCA;
        hd->hpib_data = C_UNL;
-       nhpibowait(hd);
+       if (nhpibwait(hd, MIS_BO))
+               goto senderror;
        hd->hpib_data = C_TAG + hs->sc_ba;
        hd->hpib_acr = AUX_STON;
        hd->hpib_data = C_TAG + hs->sc_ba;
        hd->hpib_acr = AUX_STON;
-       nhpibowait(hd);
+       if (nhpibwait(hd, MIS_BO))
+               goto senderror;
        hd->hpib_data = C_LAG + slave;
        hd->hpib_data = C_LAG + slave;
-       nhpibowait(hd);
+       if (nhpibwait(hd, MIS_BO))
+               goto senderror;
        if (sec != -1) {
                hd->hpib_data = C_SCG + sec;
        if (sec != -1) {
                hd->hpib_data = C_SCG + sec;
-               nhpibowait(hd);
+               if (nhpibwait(hd, MIS_BO))
+                       goto senderror;
        }
        hd->hpib_acr = AUX_GTS;
        if (cnt) {
        }
        hd->hpib_acr = AUX_GTS;
        if (cnt) {
-               while (--cnt) {
+               while (--cnt > 0) {
                        hd->hpib_data = *addr++;
                        hd->hpib_data = *addr++;
-                       if (nhpibowait(hd) < 0) {
-                               nhpibifc(hd);
-                               cnt++;
-                               goto out;
-                       }
+                       if (nhpibwait(hd, MIS_BO))
+                               goto senderror;
                }
                hd->hpib_acr = AUX_EOI;
                hd->hpib_data = *addr;
                }
                hd->hpib_acr = AUX_EOI;
                hd->hpib_data = *addr;
-               if (nhpibowait(hd) < 0) {
-                       nhpibifc(hd);
-                       cnt++;
-               }
-               else
-                       hd->hpib_acr = AUX_TCA;
+               if (nhpibwait(hd, MIS_BO))
+                       goto senderror;
+               hd->hpib_acr = AUX_TCA;
+#if 0
+               /*
+                * May be causing 345 disks to hang due to interference
+                * with PPOLL mechanism.
+                */
+               hd->hpib_data = C_UNL;
+               (void) nhpibwait(hd, MIS_BO);
+#endif
        }
        }
-out:
-       return(origcnt - cnt);
+       return(origcnt);
+senderror:
+       nhpibifc(hd);
+       return(origcnt - cnt - 1);
 }
 
 }
 
-nhpibrecv(unit, slave, sec, addr, cnt)
+nhpibrecv(unit, slave, sec, addr, origcnt)
        register char *addr;
        register char *addr;
-       register int cnt;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
-       register int origcnt = cnt;
+       register int cnt = origcnt;
 
        hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
        hd->hpib_acr = AUX_TCA;
        hd->hpib_data = C_UNL;
 
        hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
        hd->hpib_acr = AUX_TCA;
        hd->hpib_data = C_UNL;
-       nhpibowait(hd);
+       if (nhpibwait(hd, MIS_BO))
+               goto recverror;
        hd->hpib_data = C_LAG + hs->sc_ba;
        hd->hpib_acr = AUX_SLON;
        hd->hpib_data = C_LAG + hs->sc_ba;
        hd->hpib_acr = AUX_SLON;
-       nhpibowait(hd);
+       if (nhpibwait(hd, MIS_BO))
+               goto recverror;
        hd->hpib_data = C_TAG + slave;
        hd->hpib_data = C_TAG + slave;
-       nhpibowait(hd);
+       if (nhpibwait(hd, MIS_BO))
+               goto recverror;
        if (sec != -1) {
                hd->hpib_data = C_SCG + sec;
        if (sec != -1) {
                hd->hpib_data = C_SCG + sec;
-               nhpibowait(hd);
+               if (nhpibwait(hd, MIS_BO))
+                       goto recverror;
        }
        hd->hpib_acr = AUX_RHDF;
        hd->hpib_acr = AUX_GTS;
        if (cnt) {
                while (--cnt >= 0) {
        }
        hd->hpib_acr = AUX_RHDF;
        hd->hpib_acr = AUX_GTS;
        if (cnt) {
                while (--cnt >= 0) {
-                       if (nhpibiwait(hd) < 0) {
-                               nhpibifc(hd);
-                               break;
-                       }
+                       if (nhpibwait(hd, MIS_BI))
+                               goto recvbyteserror;
                        *addr++ = hd->hpib_data;
                }
                        *addr++ = hd->hpib_data;
                }
-               cnt++;
                hd->hpib_acr = AUX_TCA;
                hd->hpib_acr = AUX_TCA;
+               hd->hpib_data = (slave == 31) ? C_UNA : C_UNT;
+               (void) nhpibwait(hd, MIS_BO);
        }
        }
-       return(origcnt - cnt);
+       return(origcnt);
+recverror:
+       nhpibifc(hd);
+recvbyteserror:
+       return(origcnt - cnt - 1);
 }
 
 nhpibgo(unit, slave, sec, addr, count, rw)
 }
 
 nhpibgo(unit, slave, sec, addr, count, rw)
@@ -183,19 +196,17 @@ nhpibgo(unit, slave, sec, addr, count, rw)
                dmago(hs->sc_dq.dq_ctlr, addr, count, DMAGO_BYTE|DMAGO_READ);
                nhpibrecv(unit, slave, sec, 0, 0);
                hd->hpib_mim = MIS_END;
                dmago(hs->sc_dq.dq_ctlr, addr, count, DMAGO_BYTE|DMAGO_READ);
                nhpibrecv(unit, slave, sec, 0, 0);
                hd->hpib_mim = MIS_END;
-       }
-       else {
-               if (count == 1) {
-                       hs->sc_curcnt = 1;
-                       dmago(hs->sc_dq.dq_ctlr, addr, 1, DMAGO_BYTE);
-                       nhpibsend(unit, slave, sec, 0, 0);
-                       hd->hpib_acr = AUX_EOI;
-               }
-               else {
-                       hs->sc_curcnt = count - 1;
-                       dmago(hs->sc_dq.dq_ctlr, addr, count - 1, DMAGO_BYTE);
-                       nhpibsend(unit, slave, sec, 0, 0);
+       } else {
+               hd->hpib_mim = 0;
+               if (count < hpibdmathresh) {
+                       hs->sc_curcnt = count;
+                       nhpibsend(unit, slave, sec, addr, count);
+                       nhpibdone(unit);
+                       return;
                }
                }
+               hs->sc_curcnt = --count;
+               dmago(hs->sc_dq.dq_ctlr, addr, count, DMAGO_BYTE);
+               nhpibsend(unit, slave, sec, 0, 0);
        }
        hd->hpib_ie = IDS_IE | IDS_DMA(hs->sc_dq.dq_ctlr);
 }
        }
        hd->hpib_ie = IDS_IE | IDS_DMA(hs->sc_dq.dq_ctlr);
 }
@@ -211,19 +222,19 @@ nhpibdone(unit)
        cnt = hs->sc_curcnt;
        hs->sc_addr += cnt;
        hs->sc_count -= cnt;
        cnt = hs->sc_curcnt;
        hs->sc_addr += cnt;
        hs->sc_count -= cnt;
-       if (hs->sc_flags & HPIBF_READ) {
-               hs->sc_flags |= HPIBF_DONE;
-               hd->hpib_ie = IDS_IE;
-       } else {
+       hs->sc_flags |= HPIBF_DONE;
+       hd->hpib_ie = IDS_IE;
+       if ((hs->sc_flags & HPIBF_READ) == 0) {
                if (hs->sc_count == 1) {
                if (hs->sc_count == 1) {
-                       hs->sc_curcnt = 1;
+                       (void) nhpibwait(hd, MIS_BO);
                        hd->hpib_acr = AUX_EOI;
                        hd->hpib_acr = AUX_EOI;
-                       dmago(hs->sc_dq.dq_ctlr, hs->sc_addr, 1, DMAGO_BYTE);
-                       return;
+                       hd->hpib_data = *hs->sc_addr;
+                       hd->hpib_mim = MIS_BO;
                }
                }
-               hs->sc_flags |= HPIBF_DONE;
-               hd->hpib_ie = IDS_IE;
-               hd->hpib_mim = MIS_BO;
+#ifdef DEBUG
+               else if (hs->sc_count)
+                       panic("nhpibdone");
+#endif
        }
 }
 
        }
 }
 
@@ -232,7 +243,7 @@ nhpibintr(unit)
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
-       register struct devqueue *dq = hs->sc_sq.dq_forw;
+       register struct devqueue *dq;
        register int stat0;
        int stat1;
 
        register int stat0;
        int stat1;
 
@@ -244,6 +255,7 @@ nhpibintr(unit)
                return(0);
        stat0 = hd->hpib_mis;
        stat1 = hd->hpib_lis;
                return(0);
        stat0 = hd->hpib_mis;
        stat1 = hd->hpib_lis;
+       dq = hs->sc_sq.dq_forw;
        if (hs->sc_flags & HPIBF_IO) {
                hd->hpib_mim = 0;
                if ((hs->sc_flags & HPIBF_DONE) == 0)
        if (hs->sc_flags & HPIBF_IO) {
                hd->hpib_mim = 0;
                if ((hs->sc_flags & HPIBF_DONE) == 0)
@@ -252,28 +264,29 @@ nhpibintr(unit)
                hs->sc_flags &= ~(HPIBF_DONE|HPIBF_IO|HPIBF_READ);
                dmafree(&hs->sc_dq);
                (dq->dq_driver->d_intr)(dq->dq_unit);
                hs->sc_flags &= ~(HPIBF_DONE|HPIBF_IO|HPIBF_READ);
                dmafree(&hs->sc_dq);
                (dq->dq_driver->d_intr)(dq->dq_unit);
-               return(1);
-       }
-       if (hs->sc_flags & HPIBF_PPOLL) {
+       } else if (hs->sc_flags & HPIBF_PPOLL) {
                hd->hpib_mim = 0;
                stat0 = nhpibppoll(unit);
                if (stat0 & (0x80 >> dq->dq_slave)) {
                        hs->sc_flags &= ~HPIBF_PPOLL;
                        (dq->dq_driver->d_intr)(dq->dq_unit);
                }
                hd->hpib_mim = 0;
                stat0 = nhpibppoll(unit);
                if (stat0 & (0x80 >> dq->dq_slave)) {
                        hs->sc_flags &= ~HPIBF_PPOLL;
                        (dq->dq_driver->d_intr)(dq->dq_unit);
                }
-               return(1);
+#ifdef DEBUG
+               else
+                       printf("hpib%d: PPOLL intr bad status %x\n",
+                              unit, stat0);
+#endif
        }
        return(1);
 }
 
 nhpibppoll(unit)
        }
        return(1);
 }
 
 nhpibppoll(unit)
-       register int unit;
+       int unit;
 {
 {
-       register struct hpib_softc *hs = &hpib_softc[unit];
        register struct nhpibdevice *hd;
        register int ppoll;
 
        register struct nhpibdevice *hd;
        register int ppoll;
 
-       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       hd = (struct nhpibdevice *)hpib_softc[unit].sc_hc->hp_addr;
        hd->hpib_acr = AUX_SPP;
        DELAY(25);
        ppoll = hd->hpib_cpt;
        hd->hpib_acr = AUX_SPP;
        DELAY(25);
        ppoll = hd->hpib_cpt;
@@ -281,27 +294,13 @@ nhpibppoll(unit)
        return(ppoll);
 }
 
        return(ppoll);
 }
 
-nhpibowait(hd)
-       register struct nhpibdevice *hd;
-{
-       extern int hpibtimeout;
-       register int timo = hpibtimeout;
-
-       while ((hd->hpib_mis & MIS_BO) == 0 && --timo)
-               ;
-       if (timo == 0)
-               return(-1);
-       return(0);
-}
-
-nhpibiwait(hd)
+nhpibwait(hd, x)
        register struct nhpibdevice *hd;
 {
        register struct nhpibdevice *hd;
 {
-       extern int hpibtimeout;
        register int timo = hpibtimeout;
 
        register int timo = hpibtimeout;
 
-       while ((hd->hpib_mis & MIS_BI) == 0 && --timo)
-               ;
+       while ((hd->hpib_mis & x) == 0 && --timo)
+               DELAY(1);
        if (timo == 0)
                return(-1);
        return(0);
        if (timo == 0)
                return(-1);
        return(0);
@@ -311,12 +310,10 @@ nhpibppwatch(unit)
        register int unit;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
        register int unit;
 {
        register struct hpib_softc *hs = &hpib_softc[unit];
-       register struct devqueue *dq = hs->sc_sq.dq_forw;
-       register int slave = 0x80 >> dq->dq_slave;
 
        if ((hs->sc_flags & HPIBF_PPOLL) == 0)
                return;
 
        if ((hs->sc_flags & HPIBF_PPOLL) == 0)
                return;
-       if (nhpibppoll(unit) & slave)
+       if (nhpibppoll(unit) & (0x80 >> hs->sc_sq.dq_forw->dq_slave))
                        ((struct nhpibdevice *)hs->sc_hc->hp_addr)->hpib_mim = MIS_BO;
        else
                timeout(nhpibppwatch, unit, 1);
                        ((struct nhpibdevice *)hs->sc_hc->hp_addr)->hpib_mim = MIS_BO;
        else
                timeout(nhpibppwatch, unit, 1);
index b03b25d..dd8dac3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ppi.c       7.1 (Berkeley) %G%
+ *     @(#)ppi.c       7.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -20,8 +20,9 @@
 #include "malloc.h"
 
 #include "device.h"
 #include "malloc.h"
 
 #include "device.h"
+#include "ppiioctl.h"
 
 
-int    ppiattach(), ppistart();
+int    ppiattach(), ppistart(), ppitimo();
 struct driver ppidriver = {
        ppiattach, "ppi", ppistart,
 };
 struct driver ppidriver = {
        ppiattach, "ppi", ppistart,
 };
@@ -30,19 +31,37 @@ struct      ppi_softc {
        int     sc_flags;
        struct  devqueue sc_dq;
        struct  hp_device *sc_hd;
        int     sc_flags;
        struct  devqueue sc_dq;
        struct  hp_device *sc_hd;
+       struct  ppiparam sc_param;
+#define sc_burst sc_param.burst
+#define sc_timo  sc_param.timo
+#define sc_delay sc_param.delay
+       int     sc_sec;
 } ppi_softc[NPPI];
 
 /* sc_flags values */
 } ppi_softc[NPPI];
 
 /* sc_flags values */
-#define        PPIF_ALIVE      0x1     
-#define        PPIF_OPEN       0x2     
+#define        PPIF_ALIVE      0x01    
+#define        PPIF_OPEN       0x02    
+#define PPIF_UIO       0x04
+#define PPIF_TIMO      0x08
+#define PPIF_DELAY     0x10
 
 #define UNIT(x)                minor(x)
 
 
 #define UNIT(x)                minor(x)
 
+#ifdef DEBUG
+int    ppidebug = 0x80;
+#define PDB_FOLLOW     0x01
+#define PDB_IO         0x02
+#define PDB_NOCHECK    0x80
+#endif
+
 ppiattach(hd)
        register struct hp_device *hd;
 {
        register struct ppi_softc *sc = &ppi_softc[hd->hp_unit];
 
 ppiattach(hd)
        register struct hp_device *hd;
 {
        register struct ppi_softc *sc = &ppi_softc[hd->hp_unit];
 
+#ifdef DEBUG
+       if ((ppidebug & PDB_NOCHECK) == 0)
+#endif
        /*
         * XXX: the printer/plotter doesn't seem to really return
         * an ID but this will at least prevent us from mistaking
        /*
         * XXX: the printer/plotter doesn't seem to really return
         * an ID but this will at least prevent us from mistaking
@@ -67,9 +86,18 @@ ppiopen(dev, flags)
 
        if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0)
                return(ENXIO);
 
        if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0)
                return(ENXIO);
+#ifdef DEBUG
+       if (ppidebug & PDB_FOLLOW)
+               printf("ppiopen(%x, %x): flags %x\n",
+                      dev, flags, sc->sc_flags);
+#endif
        if (sc->sc_flags & PPIF_OPEN)
                return(EBUSY);
        sc->sc_flags |= PPIF_OPEN;
        if (sc->sc_flags & PPIF_OPEN)
                return(EBUSY);
        sc->sc_flags |= PPIF_OPEN;
+       sc->sc_burst = PPI_BURST;
+       sc->sc_timo = ppimstohz(PPI_TIMO);
+       sc->sc_delay = ppimstohz(PPI_DELAY);
+       sc->sc_sec = -1;
        return(0);
 }
 
        return(0);
 }
 
@@ -79,13 +107,34 @@ ppiclose(dev, flags)
        register int unit = UNIT(dev);
        register struct ppi_softc *sc = &ppi_softc[unit];
 
        register int unit = UNIT(dev);
        register struct ppi_softc *sc = &ppi_softc[unit];
 
+#ifdef DEBUG
+       if (ppidebug & PDB_FOLLOW)
+               printf("ppiclose(%x, %x): flags %x\n",
+                      dev, flags, sc->sc_flags);
+#endif
        sc->sc_flags &= ~PPIF_OPEN;
        return(0);
 }
 
 ppistart(unit)
        sc->sc_flags &= ~PPIF_OPEN;
        return(0);
 }
 
 ppistart(unit)
-       register int unit;
+       int unit;
+{
+#ifdef DEBUG
+       if (ppidebug & PDB_FOLLOW)
+               printf("ppistart(%x)\n", unit);
+#endif
+       ppi_softc[unit].sc_flags &= ~PPIF_DELAY;
+       wakeup(&ppi_softc[unit]);
+}
+
+ppitimo(unit)
+       int unit;
 {
 {
+#ifdef DEBUG
+       if (ppidebug & PDB_FOLLOW)
+               printf("ppitimo(%x)\n", unit);
+#endif
+       ppi_softc[unit].sc_flags &= ~(PPIF_UIO|PPIF_TIMO);
        wakeup(&ppi_softc[unit]);
 }
 
        wakeup(&ppi_softc[unit]);
 }
 
@@ -94,7 +143,11 @@ ppiread(dev, uio)
        struct uio *uio;
 {
 
        struct uio *uio;
 {
 
-       return (ppirw(dev, uio, UIO_READ));
+#ifdef DEBUG
+       if (ppidebug & PDB_FOLLOW)
+               printf("ppiread(%x, %x)\n", dev, uio);
+#endif
+       return (ppirw(dev, uio));
 }
 
 ppiwrite(dev, uio)
 }
 
 ppiwrite(dev, uio)
@@ -102,53 +155,228 @@ ppiwrite(dev, uio)
        struct uio *uio;
 {
 
        struct uio *uio;
 {
 
-       return (ppirw(dev, uio, UIO_WRITE));
+#ifdef DEBUG
+       if (ppidebug & PDB_FOLLOW)
+               printf("ppiwrite(%x, %x)\n", dev, uio);
+#endif
+       return (ppirw(dev, uio));
 }
 
 }
 
-ppirw(dev, uio, rw)
+ppirw(dev, uio)
        dev_t dev;
        register struct uio *uio;
        dev_t dev;
        register struct uio *uio;
-       enum uio_rw rw;
 {
 {
-       register struct ppi_softc *sc = &ppi_softc[UNIT(dev)];
+       int unit = UNIT(dev);
+       register struct ppi_softc *sc = &ppi_softc[unit];
        register int s, len, cnt;
        register char *cp;
        register int s, len, cnt;
        register char *cp;
-       int error = 0;
+       int error = 0, gotdata = 0;
+       int buflen;
+       char *buf;
+
+       if (uio->uio_resid == 0)
+               return(0);
 
 
-       len = MIN(CLBYTES, uio->uio_resid);
-       cp = (char *)malloc(len, M_TEMP, M_WAITOK);
+#ifdef DEBUG
+       if (ppidebug & (PDB_FOLLOW|PDB_IO))
+               printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n",
+                      dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
+                      sc->sc_burst, sc->sc_timo, uio->uio_resid);
+#endif
+       buflen = MIN(sc->sc_burst, uio->uio_resid);
+       buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
+       sc->sc_flags |= PPIF_UIO;
+       if (sc->sc_timo > 0) {
+               sc->sc_flags |= PPIF_TIMO;
+               timeout(ppitimo, unit, sc->sc_timo);
+       }
        while (uio->uio_resid > 0) {
        while (uio->uio_resid > 0) {
-               len = MIN(CLBYTES, uio->uio_resid);
-               if (rw == UIO_WRITE) {
+               len = MIN(buflen, uio->uio_resid);
+               cp = buf;
+               if (uio->uio_rw == UIO_WRITE) {
                        error = uiomove(cp, len, uio);
                        if (error)
                                break;
                }
                        error = uiomove(cp, len, uio);
                        if (error)
                                break;
                }
+again:
                s = splbio();
                s = splbio();
-               if (hpibreq(&sc->sc_dq) == 0)
-                       sleep(sc, PRIBIO + 1);
+               if ((sc->sc_flags & PPIF_UIO) && hpibreq(&sc->sc_dq) == 0)
+                       sleep(sc, PRIBIO+1);
+               /*
+                * Check if we timed out during sleep or uiomove
+                */
+               (void) splsoftclock();
+               if ((sc->sc_flags & PPIF_UIO) == 0) {
+#ifdef DEBUG
+                       if (ppidebug & PDB_IO)
+                               printf("ppirw: uiomove/sleep timo, flags %x\n",
+                                      sc->sc_flags);
+#endif
+                       if (sc->sc_flags & PPIF_TIMO) {
+                               untimeout(ppitimo, unit);
+                               sc->sc_flags &= ~PPIF_TIMO;
+                       }
+                       splx(s);
+                       break;
+               }
                splx(s);
                splx(s);
-               if (rw == UIO_WRITE)
+               /*
+                * Perform the operation
+                */
+               if (uio->uio_rw == UIO_WRITE)
                        cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
                        cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
-                               -1, cp, len);
+                                      sc->sc_sec, cp, len);
                else
                        cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
                else
                        cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
-                               -1, cp, len);
+                                      sc->sc_sec, cp, len);
                s = splbio();
                hpibfree(&sc->sc_dq);
                s = splbio();
                hpibfree(&sc->sc_dq);
+#ifdef DEBUG
+               if (ppidebug & PDB_IO)
+                       printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n",
+                              uio->uio_rw == UIO_READ ? "recv" : "send",
+                              sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                              sc->sc_sec, cp, len, cnt);
+#endif
                splx(s);
                splx(s);
-               if (rw == UIO_READ) {
-                       error = uiomove(cp, cnt, uio);
-                       if (error)
+               if (uio->uio_rw == UIO_READ) {
+                       if (cnt) {
+                               error = uiomove(cp, cnt, uio);
+                               if (error)
+                                       break;
+                               gotdata++;
+                       }
+                       /*
+                        * Didn't get anything this time, but did in the past.
+                        * Consider us done.
+                        */
+                       else if (gotdata)
                                break;
                }
                                break;
                }
-               if (cnt != len) {
-                       if (rw == UIO_WRITE)
-                               uio->uio_resid += len - cnt;
+               s = splsoftclock();
+               /*
+                * Operation timeout (or non-blocking), quit now.
+                */
+               if ((sc->sc_flags & PPIF_UIO) == 0) {
+#ifdef DEBUG
+                       if (ppidebug & PDB_IO)
+                               printf("ppirw: timeout/done\n");
+#endif
+                       splx(s);
                        break;
                }
                        break;
                }
+               /*
+                * Implement inter-read delay
+                */
+               if (sc->sc_delay > 0) {
+                       sc->sc_flags |= PPIF_DELAY;
+                       timeout(ppistart, unit, sc->sc_delay);
+                       error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0);
+                       if (error) {
+                               splx(s);
+                               break;
+                       }
+               }
+               splx(s);
+               /*
+                * Must not call uiomove again til we've used all data
+                * that we already grabbed.
+                */
+               if (uio->uio_rw == UIO_WRITE && cnt != len) {
+                       cp += cnt;
+                       len -= cnt;
+                       cnt = 0;
+                       goto again;
+               }
+       }
+       s = splsoftclock();
+       if (sc->sc_flags & PPIF_TIMO) {
+               untimeout(ppitimo, unit);
+               sc->sc_flags &= ~PPIF_TIMO;
+       }
+       if (sc->sc_flags & PPIF_DELAY) {
+               untimeout(ppistart, unit);
+               sc->sc_flags &= ~PPIF_DELAY;
+       }
+       splx(s);
+       /*
+        * Adjust for those chars that we uiomove'ed but never wrote
+        */
+       if (uio->uio_rw == UIO_WRITE && cnt != len) {
+               uio->uio_resid += (len - cnt);
+#ifdef DEBUG
+               if (ppidebug & PDB_IO)
+                       printf("ppirw: short write, adjust by %d\n",
+                              len-cnt);
+#endif
+       }
+       free(buf, M_DEVBUF);
+#ifdef DEBUG
+       if (ppidebug & (PDB_FOLLOW|PDB_IO))
+               printf("ppirw: return %d, resid %d\n", error, uio->uio_resid);
+#endif
+       return (error);
+}
+
+ppiioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       caddr_t data;
+       int flag;
+{
+       struct ppi_softc *sc = &ppi_softc[UNIT(dev)];
+       struct ppiparam *pp, *upp;
+       int error = 0;
+
+       switch (cmd) {
+       case PPIIOCGPARAM:
+               pp = &sc->sc_param;
+               upp = (struct ppiparam *)data;
+               upp->burst = pp->burst;
+               upp->timo = ppihztoms(pp->timo);
+               upp->delay = ppihztoms(pp->delay);
+               break;
+       case PPIIOCSPARAM:
+               pp = &sc->sc_param;
+               upp = (struct ppiparam *)data;
+               if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX ||
+                   upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX)
+                       return(EINVAL);
+               pp->burst = upp->burst;
+               pp->timo = ppimstohz(upp->timo);
+               pp->delay = ppimstohz(upp->delay);
+               break;
+       case PPIIOCSSEC:
+               sc->sc_sec = *(int *)data;
+               break;
+       default:
+               return(EINVAL);
        }
        }
-       free(cp, M_TEMP);
        return (error);
 }
        return (error);
 }
+
+ppihztoms(h)
+       int h;
+{
+       extern int hz;
+       register int m = h;
+
+       if (m > 0)
+               m = m * 1000 / hz;
+       return(m);
+}
+
+ppimstohz(m)
+       int m;
+{
+       extern int hz;
+       register int h = m;
+
+       if (h > 0) {
+               h = h * hz / 1000;
+               if (h == 0)
+                       h = 1000 / hz;
+       }
+       return(h);
+}
 #endif
 #endif