merge in hp300 support from Utah
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 9 May 1990 13:07:08 +0000 (05:07 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 9 May 1990 13:07:08 +0000 (05:07 -0800)
SCCS-vsn: sys/dev/cdvar.h 7.1
SCCS-vsn: sys/hp/dev/dcareg.h 7.1
SCCS-vsn: sys/hp300/dev/ctreg.h 7.1
SCCS-vsn: sys/hp/dev/device.h 7.1
SCCS-vsn: sys/hp300/dev/dcmreg.h 7.1
SCCS-vsn: sys/hp300/dev/dmareg.h 7.1
SCCS-vsn: sys/hp300/dev/dmavar.h 7.1
SCCS-vsn: sys/dev/vnioctl.h 7.1
SCCS-vsn: sys/hp300/dev/fhpibreg.h 7.1
SCCS-vsn: sys/hp300/dev/grf_dvreg.h 7.1
SCCS-vsn: sys/hp300/dev/grf_gbreg.h 7.1
SCCS-vsn: sys/hp300/dev/grf_rbreg.h 7.1
SCCS-vsn: sys/hp/dev/grfioctl.h 7.1
SCCS-vsn: sys/hp300/dev/grf_tcreg.h 7.1
SCCS-vsn: sys/hp/dev/grfvar.h 7.1
SCCS-vsn: sys/hp/dev/hilioctl.h 7.1
SCCS-vsn: sys/hp/dev/hilreg.h 7.1
SCCS-vsn: sys/hp/dev/hilvar.h 7.1
SCCS-vsn: sys/hp300/dev/hpibvar.h 7.1
SCCS-vsn: sys/hp300/dev/if_lereg.h 7.1
SCCS-vsn: sys/hp/dev/iteioctl.h 7.1
SCCS-vsn: sys/hp/dev/itereg.h 7.1
SCCS-vsn: sys/hp/dev/itevar.h 7.1
SCCS-vsn: sys/hp/dev/kbdmap.h 7.1
SCCS-vsn: sys/hp300/dev/nhpibreg.h 7.1
SCCS-vsn: sys/hp300/dev/rdreg.h 7.1
SCCS-vsn: sys/hp300/dev/scsireg.h 7.1
SCCS-vsn: sys/dev/cd.c 7.1
SCCS-vsn: sys/hp300/dev/scsivar.h 7.1
SCCS-vsn: sys/hp/dev/dca.c 7.1
SCCS-vsn: sys/hp300/dev/ct.c 7.1
SCCS-vsn: sys/hp300/dev/dcm.c 7.1
SCCS-vsn: sys/hp300/dev/dma.c 7.1
SCCS-vsn: sys/dev/vn.c 7.1
SCCS-vsn: sys/hp300/dev/fhpib.c 7.1
SCCS-vsn: sys/hp/dev/grf.c 7.1
SCCS-vsn: sys/hp300/dev/grf_dv.c 7.1
SCCS-vsn: sys/hp300/dev/grf_gb.c 7.1
SCCS-vsn: sys/hp300/dev/grf_rb.c 7.1
SCCS-vsn: sys/hp/dev/hil.c 7.1
SCCS-vsn: sys/hp300/dev/grf_tc.c 7.1
SCCS-vsn: sys/hp/dev/hil_keymaps.c 7.1
SCCS-vsn: sys/hp300/dev/hpib.c 7.1
SCCS-vsn: sys/hp/dev/ite.c 7.1
SCCS-vsn: sys/hp300/dev/if_le.c 7.1
SCCS-vsn: sys/hp300/dev/ite_dv.c 7.1
SCCS-vsn: sys/hp300/dev/ite_gb.c 7.1
SCCS-vsn: sys/hp/dev/ite_subr.c 7.1
SCCS-vsn: sys/hp300/dev/ite_rb.c 7.1
SCCS-vsn: sys/hp300/dev/ite_tc.c 7.1
SCCS-vsn: sys/hp300/dev/nhpib.c 7.1
SCCS-vsn: sys/hp300/dev/ppi.c 7.1
SCCS-vsn: sys/hp300/dev/rd.c 7.1
SCCS-vsn: sys/hp300/dev/scsi.c 7.1
SCCS-vsn: sys/hp300/dev/sd.c 7.1

55 files changed:
usr/src/sys/dev/cd.c [new file with mode: 0644]
usr/src/sys/dev/cdvar.h [new file with mode: 0644]
usr/src/sys/dev/vn.c [new file with mode: 0644]
usr/src/sys/dev/vnioctl.h [new file with mode: 0644]
usr/src/sys/hp/dev/dca.c [new file with mode: 0644]
usr/src/sys/hp/dev/dcareg.h [new file with mode: 0644]
usr/src/sys/hp/dev/device.h [new file with mode: 0644]
usr/src/sys/hp/dev/grf.c [new file with mode: 0644]
usr/src/sys/hp/dev/grfioctl.h [new file with mode: 0644]
usr/src/sys/hp/dev/grfvar.h [new file with mode: 0644]
usr/src/sys/hp/dev/hil.c [new file with mode: 0644]
usr/src/sys/hp/dev/hil_keymaps.c [new file with mode: 0644]
usr/src/sys/hp/dev/hilioctl.h [new file with mode: 0644]
usr/src/sys/hp/dev/hilreg.h [new file with mode: 0644]
usr/src/sys/hp/dev/hilvar.h [new file with mode: 0644]
usr/src/sys/hp/dev/ite.c [new file with mode: 0644]
usr/src/sys/hp/dev/ite_subr.c [new file with mode: 0644]
usr/src/sys/hp/dev/iteioctl.h [new file with mode: 0644]
usr/src/sys/hp/dev/itereg.h [new file with mode: 0644]
usr/src/sys/hp/dev/itevar.h [new file with mode: 0644]
usr/src/sys/hp/dev/kbdmap.h [new file with mode: 0644]
usr/src/sys/hp300/dev/ct.c [new file with mode: 0644]
usr/src/sys/hp300/dev/ctreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/dcm.c [new file with mode: 0644]
usr/src/sys/hp300/dev/dcmreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/dma.c [new file with mode: 0644]
usr/src/sys/hp300/dev/dmareg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/dmavar.h [new file with mode: 0644]
usr/src/sys/hp300/dev/fhpib.c [new file with mode: 0644]
usr/src/sys/hp300/dev/fhpibreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_dv.c [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_dvreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_gb.c [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_gbreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_rb.c [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_rbreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_tc.c [new file with mode: 0644]
usr/src/sys/hp300/dev/grf_tcreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/hpib.c [new file with mode: 0644]
usr/src/sys/hp300/dev/hpibvar.h [new file with mode: 0644]
usr/src/sys/hp300/dev/if_le.c [new file with mode: 0644]
usr/src/sys/hp300/dev/if_lereg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/ite_dv.c [new file with mode: 0644]
usr/src/sys/hp300/dev/ite_gb.c [new file with mode: 0644]
usr/src/sys/hp300/dev/ite_rb.c [new file with mode: 0644]
usr/src/sys/hp300/dev/ite_tc.c [new file with mode: 0644]
usr/src/sys/hp300/dev/nhpib.c [new file with mode: 0644]
usr/src/sys/hp300/dev/nhpibreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/ppi.c [new file with mode: 0644]
usr/src/sys/hp300/dev/rd.c [new file with mode: 0644]
usr/src/sys/hp300/dev/rdreg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/scsi.c [new file with mode: 0644]
usr/src/sys/hp300/dev/scsireg.h [new file with mode: 0644]
usr/src/sys/hp300/dev/scsivar.h [new file with mode: 0644]
usr/src/sys/hp300/dev/sd.c [new file with mode: 0644]

diff --git a/usr/src/sys/dev/cd.c b/usr/src/sys/dev/cd.c
new file mode 100644 (file)
index 0000000..59bafa3
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: cd.c 1.4 89/09/17$
+ *
+ *     @(#)cd.c        7.1 (Berkeley) %G%
+ */
+
+/*
+ * "Concatenated" disk driver.
+ */
+#include "cd.h"
+#if NCD > 0
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "dkstat.h"
+#include "buf.h"
+#include "malloc.h"
+#include "conf.h"
+
+#include "cdvar.h"
+
+#ifdef DEBUG
+int cddebug = 0x00;
+#define CDB_FOLLOW     0x01
+#define CDB_INIT       0x02
+#define CDB_IO         0x04
+#endif
+
+struct buf cdbuf[NCD];
+struct buf *cdbuffer();
+int    cdiodone();
+
+#define        cdunit(x)       ((minor(x) >> 3) & 0x7) /* for consistency */
+
+#define        getcbuf()       \
+       ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
+#define putcbuf(bp)    \
+       free((caddr_t)(bp), M_DEVBUF)
+
+struct cd_softc {
+       int              sc_flags;              /* flags */
+       size_t           sc_size;               /* size of cd */
+       int              sc_ileave;             /* interleave */
+       int              sc_ncdisks;            /* number of components */
+       struct cdcinfo   sc_cinfo[NCDISKS];     /* component info */
+       struct cdiinfo   *sc_itable;            /* interleave table */
+       int              sc_usecnt;             /* number of requests active */
+       struct buf       *sc_bp;                /* "current" request */
+       int              sc_dk;                 /* disk index */
+} cd_softc[NCD];
+
+/* sc_flags */
+#define        CDF_ALIVE       0x01
+#define CDF_INITED     0x02
+
+cdinit(cd)
+       struct cddevice *cd;
+{
+       register struct cd_softc *cs = &cd_softc[cd->cd_unit];
+       register struct cdcinfo *ci;
+       register size_t size;
+       register int ix;
+       size_t minsize;
+       dev_t dev;
+
+#ifdef DEBUG
+       if (cddebug & (CDB_FOLLOW|CDB_INIT))
+               printf("cdinit: unit %d\n", cd->cd_unit);
+#endif
+       cs->sc_dk = cd->cd_dk;
+       cs->sc_size = 0;
+       cs->sc_ileave = cd->cd_interleave;
+       cs->sc_ncdisks = 0;
+       /*
+        * Verify that each component piece exists and record
+        * relevant information about it.
+        */
+       minsize = 0;
+       for (ix = 0; ix < NCDISKS; ix++) {
+               if ((dev = cd->cd_dev[ix]) == NODEV)
+                       break;
+               ci = &cs->sc_cinfo[ix];
+               ci->ci_dev = dev;
+               /*
+                * Calculate size (truncated to interleave boundary
+                * if necessary.
+                */
+               if (bdevsw[major(dev)].d_psize) {
+                       size = (*bdevsw[major(dev)].d_psize)(dev);
+                       if (size <= 0)
+                               size = 0;
+               } else
+                       size = 0;
+               if (cs->sc_ileave > 1)
+                       size -= size % cs->sc_ileave;
+               if (size == 0)
+                       return(0);
+               if (minsize == 0 || size < minsize)
+                       minsize = size;
+               ci->ci_size = size;
+               cs->sc_size += size;
+               cs->sc_ncdisks++;
+       }
+       /*
+        * If uniform interleave is desired set all sizes to that of
+        * the smallest component.
+        */
+       if (cd->cd_flags & CDF_UNIFORM) {
+               for (ci = cs->sc_cinfo;
+                    ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
+                       ci->ci_size = minsize;
+               cs->sc_size = cs->sc_ncdisks * minsize;
+       }
+       /*
+        * Construct the interleave table
+        */
+       if (!cdinterleave(cs))
+               return(0);
+       if (cd->cd_dk >= 0)
+               dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */
+       printf("cd%d: %d components (%d blocks) concatenated",
+              cd->cd_unit, cs->sc_ncdisks, cs->sc_size);
+       if (cs->sc_ileave)
+               printf(", %d block interleave\n", cs->sc_ileave);
+       else
+               printf(" serially\n");
+       cs->sc_flags = CDF_ALIVE | CDF_INITED;
+       return(1);
+}
+
+cdinterleave(cs)
+       register struct cd_softc *cs;
+{
+       register struct cdcinfo *ci, *smallci;
+       register struct cdiinfo *ii;
+       register daddr_t bn, lbn;
+       register int ix;
+       u_long size;
+
+#ifdef DEBUG
+       if (cddebug & CDB_INIT)
+               printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
+#endif
+       /*
+        * Allocate an interleave table.
+        * Chances are this is too big, but we don't care.
+        */
+       size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo);
+       cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
+       bzero((caddr_t)cs->sc_itable, size);
+       /*
+        * Trivial case: no interleave (actually interleave of disk size).
+        * Each table entry represent a single component in its entirety.
+        */
+       if (cs->sc_ileave == 0) {
+               bn = 0;
+               ii = cs->sc_itable;
+               for (ix = 0; ix < cs->sc_ncdisks; ix++) {
+                       ii->ii_ndisk = 1;
+                       ii->ii_startblk = bn;
+                       ii->ii_startoff = 0;
+                       ii->ii_index[0] = ix;
+                       bn += cs->sc_cinfo[ix].ci_size;
+                       ii++;
+               }
+               ii->ii_ndisk = 0;
+#ifdef DEBUG
+               if (cddebug & CDB_INIT)
+                       printiinfo(cs->sc_itable);
+#endif
+               return(1);
+       }
+       /*
+        * The following isn't fast or pretty; it doesn't have to be.
+        */
+       size = 0;
+       bn = lbn = 0;
+       for (ii = cs->sc_itable; ; ii++) {
+               /*
+                * Locate the smallest of the remaining components
+                */
+               smallci = NULL;
+               for (ci = cs->sc_cinfo;
+                    ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
+                       if (ci->ci_size > size &&
+                           (smallci == NULL ||
+                            ci->ci_size < smallci->ci_size))
+                               smallci = ci;
+               /*
+                * Nobody left, all done
+                */
+               if (smallci == NULL) {
+                       ii->ii_ndisk = 0;
+                       break;
+               }
+               /*
+                * Record starting logical block and component offset
+                */
+               ii->ii_startblk = bn / cs->sc_ileave;
+               ii->ii_startoff = lbn;
+               /*
+                * Determine how many disks take part in this interleave
+                * and record their indices.
+                */
+               ix = 0;
+               for (ci = cs->sc_cinfo;
+                    ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
+                       if (ci->ci_size >= smallci->ci_size)
+                               ii->ii_index[ix++] = ci - cs->sc_cinfo;
+               ii->ii_ndisk = ix;
+               bn += ix * (smallci->ci_size - size);
+               lbn = smallci->ci_size / cs->sc_ileave;
+               size = smallci->ci_size;
+       }
+#ifdef DEBUG
+       if (cddebug & CDB_INIT)
+               printiinfo(cs->sc_itable);
+#endif
+       return(1);
+}
+
+#ifdef DEBUG
+printiinfo(ii)
+       struct cdiinfo *ii;
+{
+       register int ix, i;
+
+       for (ix = 0; ii->ii_ndisk; ix++, ii++) {
+               printf(" itab[%d]: #dk %d sblk %d soff %d",
+                      ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
+               for (i = 0; i < ii->ii_ndisk; i++)
+                       printf(" %d", ii->ii_index[i]);
+               printf("\n");
+       }
+}
+#endif
+
+cdopen(dev, flags)
+       dev_t dev;
+{
+       int unit = cdunit(dev);
+       register struct cd_softc *cs = &cd_softc[unit];
+
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdopen(%x, %x)\n", dev, flags);
+#endif
+       if (unit >= NCD || (cs->sc_flags & CDF_ALIVE) == 0)
+               return(ENXIO);
+       return(0);
+}
+
+cdstrategy(bp)
+       register struct buf *bp;
+{
+       register int unit = cdunit(bp->b_dev);
+       register struct cd_softc *cs = &cd_softc[unit];
+       register int bn, sz;
+       int s;
+
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdstrategy(%x): unit %d\n", bp, unit);
+#endif
+       if ((cs->sc_flags & CDF_INITED) == 0) {
+               bp->b_error = ENXIO;
+               goto bad;
+       }
+       bn = bp->b_blkno;
+       sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT;
+       bp->b_resid = bp->b_bcount;
+       if (bn < 0 || bn + sz > cs->sc_size) {
+               if (bn == cs->sc_size)
+                       goto done;
+               bp->b_error = EINVAL;
+               goto bad;
+       }
+       /*
+        * "Start" the unit.
+        * XXX: the use of sc_bp is just to retain the "traditional"
+        * interface to the start routine.
+        */
+       s = splbio();
+       cs->sc_bp = bp;
+       cdstart(unit);
+       splx(s);
+       return;
+bad:
+       bp->b_flags |= B_ERROR;
+done:
+       iodone(bp);
+}
+
+cdstart(unit)
+       int unit;
+{
+       register struct cd_softc *cs = &cd_softc[unit];
+       register struct buf *bp = cs->sc_bp;
+       register long bcount, rcount;
+       struct buf *cbp;
+       caddr_t addr;
+       daddr_t bn;
+
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdstart(%d)\n", unit);
+#endif
+       /*
+        * Instumentation (not real meaningful)
+        */
+       cs->sc_usecnt++;
+       if (cs->sc_dk >= 0) {
+               dk_busy |= 1 << cs->sc_dk;
+               dk_xfer[cs->sc_dk]++;
+               dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
+       }
+       /*
+        * Allocate component buffers and fire off the requests
+        */
+       bn = bp->b_blkno;
+       addr = bp->b_un.b_addr;
+       for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
+               cbp = cdbuffer(cs, bp, bn, addr, bcount);
+               rcount = cbp->b_bcount;
+               (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp);
+               bn += btodb(rcount);
+               addr += rcount;
+       }
+}
+
+/*
+ * Build a component buffer header.
+ */
+struct buf *
+cdbuffer(cs, bp, bn, addr, bcount)
+       register struct cd_softc *cs;
+       struct buf *bp;
+       daddr_t bn;
+       caddr_t addr;
+       long bcount;
+{
+       register struct cdcinfo *ci;
+       register struct buf *cbp;
+       register daddr_t cbn, cboff;
+
+#ifdef DEBUG
+       if (cddebug & CDB_IO)
+               printf("cdbuffer(%x, %x, %d, %x, %d)\n",
+                      cs, bp, bn, addr, bcount);
+#endif
+       /*
+        * Determine which component bn falls in.
+        */
+       cbn = bn;
+       cboff = 0;
+       /*
+        * Serially concatenated
+        */
+       if (cs->sc_ileave == 0) {
+               register daddr_t sblk;
+
+               sblk = 0;
+               for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
+                       sblk += ci->ci_size;
+               cbn -= sblk;
+       }
+       /*
+        * Interleaved
+        */
+       else {
+               register struct cdiinfo *ii;
+               int cdisk, off;
+
+               cboff = cbn % cs->sc_ileave;
+               cbn /= cs->sc_ileave;
+               for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
+                       if (ii->ii_startblk > cbn)
+                               break;
+               ii--;
+               off = cbn - ii->ii_startblk;
+               if (ii->ii_ndisk == 1) {
+                       cdisk = ii->ii_index[0];
+                       cbn = ii->ii_startoff + off;
+               } else {
+                       cdisk = ii->ii_index[off % ii->ii_ndisk];
+                       cbn = ii->ii_startoff + off / ii->ii_ndisk;
+               }
+               cbn *= cs->sc_ileave;
+               ci = &cs->sc_cinfo[cdisk];
+       }
+       /*
+        * Fill in the component buf structure.
+        */
+       cbp = getcbuf();
+       cbp->b_flags = bp->b_flags | B_CALL;
+       cbp->b_iodone = cdiodone;
+       cbp->b_proc = bp->b_proc;
+       cbp->b_dev = ci->ci_dev;
+       cbp->b_blkno = cbn + cboff;
+       cbp->b_un.b_addr = addr;
+       if (cs->sc_ileave == 0)
+               cbp->b_bcount = dbtob(ci->ci_size - cbn);
+       else
+               cbp->b_bcount = dbtob(cs->sc_ileave - cboff);
+       if (cbp->b_bcount > bcount)
+               cbp->b_bcount = bcount;
+       /*
+        * XXX: context for cdiodone
+        */
+       cbp->b_vp = (struct vnode *)bp;
+       cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo);
+#ifdef DEBUG
+       if (cddebug & CDB_IO)
+               printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
+                      ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno,
+                      cbp->b_un.b_addr, cbp->b_bcount);
+#endif
+       return(cbp);
+}
+
+cdintr(unit)
+       int unit;
+{
+       register struct cd_softc *cs = &cd_softc[unit];
+       register struct buf *bp = cs->sc_bp;
+
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdintr(%d)\n", unit);
+#endif
+       /*
+        * Request is done for better or worse, wakeup the top half.
+        */
+       if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0)
+               dk_busy &= ~(1 << cs->sc_dk);
+       if (bp->b_flags & B_ERROR)
+               bp->b_resid = bp->b_bcount;
+       iodone(bp);
+}
+
+/*
+ * Called by iodone at interrupt time.
+ * Mark the component as done and if all components are done,
+ * take a cd interrupt.
+ */
+cdiodone(cbp)
+       register struct buf *cbp;
+{
+       register struct buf *bp = (struct buf *)cbp->b_vp;      /* XXX */
+       register int unit = (cbp->b_pfcent >> 16) & 0xFFFF;     /* XXX */
+       int count, s;
+
+       s = splbio();
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdiodone(%x)\n", cbp);
+       if (cddebug & CDB_IO) {
+               printf("cdiodone: bp %x bcount %d resid %d\n",
+                      bp, bp->b_bcount, bp->b_resid);
+               printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
+                      cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp,
+                      cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount);
+       }
+#endif
+
+       if (cbp->b_flags & B_ERROR) {
+               bp->b_flags |= B_ERROR;
+               bp->b_error = geterror(cbp);
+#ifdef DEBUG
+               printf("cd%d: error %d on component %d\n",
+                      unit, bp->b_error, cbp->b_pfcent & 0xFFFF);
+#endif
+       }
+       count = cbp->b_bcount;
+       putcbuf(cbp);
+
+       /*
+        * If all done, "interrupt".
+        * Again, sc_bp is only used to preserve the traditional interface.
+        */
+       bp->b_resid -= count;
+       if (bp->b_resid < 0)
+               panic("cdiodone: count");
+       if (bp->b_resid == 0) {
+               cd_softc[unit].sc_bp = bp;
+               cdintr(unit);
+       }
+       splx(s);
+}
+
+cdread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = cdunit(dev);
+
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdread(%x, %x)\n", dev, uio);
+#endif
+       return(physio(cdstrategy, &cdbuf[unit], dev, B_READ, minphys, uio));
+}
+
+cdwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = cdunit(dev);
+
+#ifdef DEBUG
+       if (cddebug & CDB_FOLLOW)
+               printf("cdwrite(%x, %x)\n", dev, uio);
+#endif
+       return(physio(cdstrategy, &cdbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+cdioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       caddr_t data;
+       int flag;
+{
+       return(EINVAL);
+}
+
+cdsize(dev)
+       dev_t dev;
+{
+       int unit = cdunit(dev);
+       register struct cd_softc *cs = &cd_softc[unit];
+
+       if (unit >= NCD || (cs->sc_flags & CDF_INITED) == 0)
+               return(-1);
+       return(cs->sc_size);
+}
+
+cddump(dev)
+{
+       return(ENXIO);
+}
+#endif
diff --git a/usr/src/sys/dev/cdvar.h b/usr/src/sys/dev/cdvar.h
new file mode 100644 (file)
index 0000000..89ce81b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: cdvar.h 1.4 89/09/17$
+ *
+ *     @(#)cdvar.h     7.1 (Berkeley) %G%
+ */
+
+#define        NCDISKS 8                       /* max # of component disks */
+
+/*
+ * A concatenated disk is described at config time by this structure.
+ */
+struct cddevice {
+       int     cd_unit;                /* logical unit of this cd */
+       int     cd_interleave;          /* interleave (DEV_BSIZE blocks) */
+       int     cd_flags;               /* misc. information */
+       int     cd_dk;                  /* disk number */
+       dev_t   cd_dev[NCDISKS];        /* component devices */
+};
+
+/* cd_flags */
+#define        CDF_SWAP        0x01    /* interleave should be dmmax */
+#define CDF_UNIFORM    0x02    /* use LCD of sizes for uniform interleave */
+
+/*
+ * Component info table.
+ * Describes a single component of a concatenated disk.
+ */
+struct cdcinfo {
+       dev_t           ci_dev;  /* devno */
+       size_t          ci_size; /* size */
+};
+
+/*
+ * Interleave description table.
+ * Computed at boot time to speed irregular-interleave lookups.
+ * The idea is that we interleave in "groups".  First we interleave
+ * evenly over all component disks up to the size of the smallest
+ * component (the first group), then we interleave evenly over all
+ * remaining disks up to the size of the next-smallest (second group),
+ * and so on.
+ *
+ * Each table entry describes the interleave characteristics of one
+ * of these groups.  For example if a concatenated disk consisted of
+ * three components of 5, 3, and 7 DEV_BSIZE blocks interleaved at
+ * DEV_BSIZE (1), the table would have three entries:
+ *
+ *     ndisk   startblk        startoff        dev
+ *     3       0               0               0, 1, 2
+ *     2       9               3               0, 2
+ *     1       13              5               2
+ *     0       -               -               -
+ *
+ * which says that the first nine blocks (0-8) are interleaved over
+ * 3 disks (0, 1, 2) starting at block offset 0 on any component disk,
+ * the next 4 blocks (9-12) are interleaved over 2 disks (0, 2) starting
+ * at component block 3, and the remaining blocks (13-14) are on disk
+ * 2 starting at offset 5.
+ */
+struct cdiinfo {
+       int     ii_ndisk;       /* # of disks range is interleaved over */
+       daddr_t ii_startblk;    /* starting scaled block # for range */
+       daddr_t ii_startoff;    /* starting component offset (block #) */
+       char    ii_index[NCDISKS];/* ordered list of components in range */
+};
+
+#ifdef KERNEL
+extern struct cddevice cddevice[];
+#endif
diff --git a/usr/src/sys/dev/vn.c b/usr/src/sys/dev/vn.c
new file mode 100644 (file)
index 0000000..3f69db4
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: fd.c 1.3 89/12/03$
+ *
+ *     @(#)vn.c        7.1 (Berkeley) %G%
+ */
+
+/*
+ * File (vnode) disk driver.
+ *
+ * Block/character interface to a vnode.  Note that this uses the
+ * VOP_BMAP/VOP_STRATEGY interface to the vnode instead of a simple
+ * VOP_RDWR.  We do this to avoid distorting the local buffer cache.
+ *
+ * NOTE: There is a security issue involved with this driver.
+ * Once mounted all access to the contents of the "mapped" file via
+ * the special file is controlled by the permissions on the special
+ * file, the protection of the mapped file is ignored (effectively,
+ * by using root credentials in all transactions).
+ */
+#include "fd.h"
+#if NFD > 0
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "errno.h"
+#include "dkstat.h"
+#include "ioctl.h"
+#include "user.h"
+#include "vfs.h"
+#include "vnode.h"
+#include "file.h"
+#include "uio.h"
+#include "malloc.h"
+
+#include "fdioctl.h"
+
+#ifdef DEBUG
+int fddebug = 0x00;
+#define FDB_FOLLOW     0x01
+#define FDB_INIT       0x02
+#define FDB_IO         0x04
+#endif
+
+struct buf fdbuf[NFD];
+struct buf fdtab[NFD];
+
+#define b_cylin        b_resid
+
+#define        fdunit(x)       ((minor(x) >> 3) & 0x7) /* for consistency */
+
+#define        getfdbuf()      \
+       ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
+#define putfdbuf(bp)   \
+       free((caddr_t)(bp), M_DEVBUF)
+
+struct fd_softc {
+       int              sc_flags;      /* flags */
+       size_t           sc_size;       /* size of fd */
+       struct vnode    *sc_vp;         /* vnode */
+       struct ucred    *sc_cred;       /* credentials */
+       int              sc_maxactive;  /* max # of active requests */
+} fd_softc[NFD];
+
+/* sc_flags */
+#define        FDF_ALIVE       0x01
+#define FDF_INITED     0x02
+
+fdopen(dev, flags)
+       dev_t dev;
+{
+       int unit = fdunit(dev);
+
+#ifdef DEBUG
+       if (fddebug & FDB_FOLLOW)
+               printf("fdopen(%x, %x)\n", dev, flags);
+#endif
+       if (unit >= NFD)
+               return(ENXIO);
+       return(0);
+}
+
+/*
+ * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
+ * Note that this driver can only be used for swapping over NFS on the hp
+ * since nfs_strategy on the vax cannot handle u-areas and page tables.
+ */
+fdstrategy(bp)
+       register struct buf *bp;
+{
+       int unit = fdunit(bp->b_dev);
+       register struct fd_softc *fs = &fd_softc[unit];
+       register struct buf *nbp;
+       register int bn, bsize, resid;
+       register caddr_t addr;
+       int sz, flags;
+       extern int fdiodone();
+
+#ifdef DEBUG
+       if (fddebug & FDB_FOLLOW)
+               printf("fdstrategy(%x): unit %d\n", bp, unit);
+#endif
+       if ((fs->sc_flags & FDF_INITED) == 0) {
+               bp->b_error = ENXIO;
+               bp->b_flags |= B_ERROR;
+               iodone(bp);
+               return;
+       }
+       bn = bp->b_blkno;
+       sz = howmany(bp->b_bcount, DEV_BSIZE);
+       bp->b_resid = bp->b_bcount;
+       if (bn < 0 || bn + sz > fs->sc_size) {
+               if (bn != fs->sc_size) {
+                       bp->b_error = EINVAL;
+                       bp->b_flags |= B_ERROR;
+               }
+               iodone(bp);
+               return;
+       }
+       bn = dbtob(bn);
+       bsize = fs->sc_vp->v_vfsp->vfs_bsize;
+       addr = bp->b_un.b_addr;
+       flags = bp->b_flags | B_CALL;
+       for (resid = bp->b_resid; resid; resid -= sz) {
+               struct vnode *vp;
+               daddr_t nbn;
+               int off, s;
+
+               nbp = getfdbuf();
+               off = bn % bsize;
+               sz = MIN(bsize - off, resid);
+               (void) VOP_BMAP(fs->sc_vp, bn / bsize, &vp, &nbn);
+#ifdef DEBUG
+               if (fddebug & FDB_IO)
+                       printf("fdstrategy: vp %x/%x bn %x/%x dev %x\n",
+                              fs->sc_vp, vp, bn, nbn, vp->v_rdev);
+#endif
+               nbp->b_flags = flags;
+               nbp->b_bcount = sz;
+               nbp->b_bufsize = bp->b_bufsize;
+               nbp->b_error = 0;
+               nbp->b_dev = vp->v_rdev;
+               nbp->b_un.b_addr = addr;
+               nbp->b_blkno = nbn + btodb(off);
+               nbp->b_proc = bp->b_proc;
+               nbp->b_iodone = fdiodone;
+               nbp->b_vp = vp;
+               nbp->b_pfcent = (int) bp;       /* XXX */
+               /*
+                * Just sort by block number
+                */
+               nbp->b_cylin = nbp->b_blkno;
+               s = splbio();
+               disksort(&fdtab[unit], nbp);
+               if (fdtab[unit].b_active < fs->sc_maxactive) {
+                       fdtab[unit].b_active++;
+                       fdstart(unit);
+               }
+               splx(s);
+               bn += sz;
+               addr += sz;
+       }
+}
+
+/*
+ * Feed requests sequentially.
+ * We do it this way to keep from flooding NFS servers if we are connected
+ * to an NFS file.  This places the burden on the client rather than the
+ * server.
+ */
+fdstart(unit)
+{
+       register struct fd_softc *fs = &fd_softc[unit];
+       register struct buf *bp;
+
+       /*
+        * Dequeue now since lower level strategy routine might
+        * queue using same links
+        */
+       bp = fdtab[unit].b_actf;
+       fdtab[unit].b_actf = bp->b_actf;
+#ifdef DEBUG
+       if (fddebug & FDB_IO)
+               printf("fdstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
+                      unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
+                      bp->b_bcount);
+#endif
+       VOP_STRATEGY(bp);
+}
+
+fdiodone(bp)
+       register struct buf *bp;
+{
+       register struct buf *pbp = (struct buf *)bp->b_pfcent;  /* XXX */
+       register int unit = fdunit(pbp->b_dev);
+       int s;
+
+       s = splbio();
+#ifdef DEBUG
+       if (fddebug & FDB_IO)
+               printf("fdiodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
+                      unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
+                      bp->b_bcount);
+#endif
+       if (bp->b_error) {
+#ifdef DEBUG
+               if (fddebug & FDB_IO)
+                       printf("fdiodone: bp %x error %d\n", bp, bp->b_error);
+#endif
+               pbp->b_flags |= B_ERROR;
+               pbp->b_error = geterror(bp);
+       }
+       pbp->b_resid -= bp->b_bcount;
+       putfdbuf(bp);
+       if (pbp->b_resid == 0) {
+#ifdef DEBUG
+               if (fddebug & FDB_IO)
+                       printf("fdiodone: pbp %x iodone\n", pbp);
+#endif
+               iodone(pbp);
+       }
+       if (fdtab[unit].b_actf)
+               fdstart(unit);
+       else
+               fdtab[unit].b_active--;
+       splx(s);
+}
+
+fdread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = fdunit(dev);
+
+#ifdef DEBUG
+       if (fddebug & FDB_FOLLOW)
+               printf("fdread(%x, %x)\n", dev, uio);
+#endif
+       return(physio(fdstrategy, &fdbuf[unit], dev, B_READ, minphys, uio));
+}
+
+fdwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = fdunit(dev);
+
+#ifdef DEBUG
+       if (fddebug & FDB_FOLLOW)
+               printf("fdwrite(%x, %x)\n", dev, uio);
+#endif
+       return(physio(fdstrategy, &fdbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+/* ARGSUSED */
+fdioctl(dev, cmd, data, flag)
+       dev_t dev;
+       u_long cmd;
+       caddr_t data;
+       int flag;
+{
+       int unit = fdunit(dev);
+       register struct fd_softc *fs;
+       struct fd_ioctl *fio;
+       struct vattr vattr;
+       struct vnode *vp;
+       int error;
+
+#ifdef DEBUG
+       if (fddebug & FDB_FOLLOW)
+               printf("fdioctl(%x, %x, %x, %x): unit %d\n",
+                      dev, cmd, data, flag, unit);
+#endif
+       error = suser(u.u_cred, &u.u_acflag);
+       if (error)
+               return (error);
+       if (unit >= NFD)
+               return (ENXIO);
+
+       fs = &fd_softc[unit];
+       fio = (struct fd_ioctl *)data;
+       switch (cmd) {
+
+       case FDIOCSET:
+               if (fs->sc_flags & FDF_INITED)
+                       return(EBUSY);
+               /*
+                * Always open for read and write.
+                * This is probably bogus, but it lets vn_open()
+                * weed out directories, sockets, etc. so we don't
+                * have to worry about them.
+                */
+               error = vn_open(fio->fd_file, UIO_USERSPACE,
+                               FREAD|FWRITE, 0, &vp);
+               if (error)
+                       return(error);
+               error = VOP_GETATTR(vp, &vattr, u.u_cred);
+               if (error) {
+                       vn_close(vp, FREAD|FWRITE);
+                       VN_RELE(vp);
+                       return(error);
+               }
+               fs->sc_vp = vp;
+               fs->sc_size = btodb(vattr.va_size);     /* note truncation */
+               error = fdsetcred(fs);
+               if (error) {
+                       vn_close(vp, FREAD|FWRITE);
+                       VN_RELE(vp);
+                       return(error);
+               }
+               fdthrottle(fs, vp);
+               fio->fd_size = dbtob(fs->sc_size);
+               fs->sc_flags |= FDF_INITED;
+#ifdef DEBUG
+               if (fddebug & FDB_INIT)
+                       printf("fdioctl: SET vp %x size %x\n",
+                              fs->sc_vp, fs->sc_size);
+#endif
+               break;
+
+       case FDIOCCLR:
+               if ((fs->sc_flags & FDF_INITED) == 0)
+                       return(ENXIO);
+               fdclear(fs);
+#ifdef DEBUG
+               if (fddebug & FDB_INIT)
+                       printf("fdioctl: CLRed\n");
+#endif
+               break;
+
+       default:
+               return(ENXIO);
+       }
+       return(0);
+}
+
+/*
+ * Duplicate the current processes' credentials.  Since we are called only
+ * as the result of a SET ioctl and only root can do that, any future access
+ * to this "disk" is essentially as root.  Note that credentials may change
+ * if some other uid can write directly to the mapped file (NFS).
+ */
+fdsetcred(fs)
+       register struct fd_softc *fs;
+{
+       struct uio auio;
+       struct iovec aiov;
+       char tmpbuf[DEV_BSIZE];
+
+       fs->sc_cred = crdup(u.u_cred);
+       /* XXX: Horrible kludge to establish credentials for NFS */
+       aiov.iov_base = tmpbuf;
+       aiov.iov_len = MIN(DEV_BSIZE, dbtob(fs->sc_size));
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       auio.uio_offset = 0;
+       auio.uio_rw = UIO_READ;
+       auio.uio_segflg = UIO_SYSSPACE;
+       auio.uio_resid = aiov.iov_len;
+       return(VOP_READ(fs->sc_vp, &auio, 0, fs->sc_cred));
+}
+
+/*
+ * Set maxactive based on FS type
+ */
+fdthrottle(fs, vp)
+       register struct fd_softc *fs;
+       struct vnode *vp;
+{
+       extern struct vnodeops ufs_vnodeops, nfs_vnodeops;
+
+       if (vp->v_op == &nfs_vnodeops)
+               fs->sc_maxactive = 2;
+       else
+               fs->sc_maxactive = 8;
+
+       if (fs->sc_maxactive < 1)
+               fs->sc_maxactive = 1;
+}
+
+fdshutdown()
+{
+       register struct fd_softc *fs;
+
+       for (fs = &fd_softc[0]; fs < &fd_softc[NFD]; fs++)
+               if (fs->sc_flags & FDF_INITED)
+                       fdclear(fs);
+}
+
+fdclear(fs)
+       register struct fd_softc *fs;
+{
+       register struct vnode *vp = fs->sc_vp;
+
+#ifdef DEBUG
+       if (fddebug & FDB_FOLLOW)
+               printf("fdclear(%x): vp %x\n", vp);
+#endif
+       fs->sc_flags &= ~FDF_INITED;
+       if (vp == (struct vnode *)0)
+               panic("fdioctl: null vp");
+#if 0
+       /* XXX - this doesn't work right now */
+       (void) VOP_FSYNC(vp, fs->sc_cred);
+#endif
+       vn_close(vp, FREAD|FWRITE);
+       VN_RELE(vp);
+       crfree(fs->sc_cred);
+       fs->sc_vp = (struct vnode *)0;
+       fs->sc_cred = (struct ucred *)0;
+       fs->sc_size = 0;
+}
+
+fdsize(dev)
+       dev_t dev;
+{
+       int unit = fdunit(dev);
+       register struct fd_softc *fs = &fd_softc[unit];
+
+       if (unit >= NFD || (fs->sc_flags & FDF_INITED) == 0)
+               return(-1);
+       return(fs->sc_size);
+}
+
+fddump(dev)
+{
+       return(ENXIO);
+}
+#endif
diff --git a/usr/src/sys/dev/vnioctl.h b/usr/src/sys/dev/vnioctl.h
new file mode 100644 (file)
index 0000000..1306258
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: fdioctl.h 1.1 89/11/20$
+ *
+ *     @(#)vnioctl.h   7.1 (Berkeley) %G%
+ */
+
+/*
+ * Ioctl definitions for file (vnode) disk pseudo-device.
+ */
+
+#define FDISKFILE      "/etc/fdisks"   /* default config file */
+
+struct fd_ioctl {
+       char    *fd_file;       /* pathname of file to mount */
+       int     fd_size;        /* (returned) size of disk */
+};
+
+/*
+ * Before you can use a unit, it must be configured with FDIOCSET.
+ * The configuration persists across opens and closes of the device;
+ * an FDIOCCLR must be used to reset a configuration.  An attempt to
+ * FDIOCSET an already active unit will return EBUSY.
+ */
+#define FDIOCSET       _IOWR('F', 0, struct fd_ioctl)  /* enable disk */
+#define FDIOCCLR       _IOW('F', 1, struct fd_ioctl)   /* disable disk */
diff --git a/usr/src/sys/hp/dev/dca.c b/usr/src/sys/hp/dev/dca.c
new file mode 100644 (file)
index 0000000..e6be461
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)dca.c       7.1 (Berkeley) %G%
+ */
+
+#include "dca.h"
+#if NDCA > 0
+/*
+ *  98626/98644/internal serial interface
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "device.h"
+#include "dcareg.h"
+#include "machine/cpu.h"
+#include "machine/isr.h"
+
+int    dcaprobe();
+struct driver dcadriver = {
+       dcaprobe, "dca",
+};
+
+int    dcastart(), dcaparam(), dcaintr();
+int    dcasoftCAR;
+int    dca_active;
+int    ndca = NDCA;
+int    dcaconsole = -1;
+int    dcadefaultrate = TTYDEF_SPEED;
+struct dcadevice *dca_addr[NDCA];
+struct tty dca_tty[NDCA];
+struct isr dcaisr[NDCA];
+
+struct speedtab dcaspeedtab[] = {
+       0,      0,
+       50,     DCABRD(50),
+       75,     DCABRD(75),
+       110,    DCABRD(110),
+       134,    DCABRD(134),
+       150,    DCABRD(150),
+       200,    DCABRD(200),
+       300,    DCABRD(300),
+       600,    DCABRD(600),
+       1200,   DCABRD(1200),
+       1800,   DCABRD(1800),
+       2400,   DCABRD(2400),
+       4800,   DCABRD(4800),
+       9600,   DCABRD(9600),
+       19200,  DCABRD(19200),
+       38400,  DCABRD(38400),
+       -1,     -1
+};
+
+extern struct tty *constty;
+#ifdef KGDB
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+#define        UNIT(x)         minor(x)
+
+dcaprobe(hd)
+       register struct hp_device *hd;
+{
+       register struct dcadevice *dca;
+       register int unit;
+
+       dca = (struct dcadevice *)hd->hp_addr;
+       if (dca->dca_irid != DCAID0 &&
+           dca->dca_irid != DCAREMID0 &&
+           dca->dca_irid != DCAID1 &&
+           dca->dca_irid != DCAREMID1)
+               return (0);
+       unit = hd->hp_unit;
+       if (unit == dcaconsole)
+               DELAY(100000);
+       dca->dca_irid = 0xFF;
+       DELAY(100);
+
+       hd->hp_ipl = DCAIPL(dca->dca_ic);
+       dcaisr[unit].isr_ipl = hd->hp_ipl;
+       dcaisr[unit].isr_arg = unit;
+       dcaisr[unit].isr_intr = dcaintr;
+       dca_addr[unit] = dca;
+       dca_active |= 1 << unit;
+       dcasoftCAR = hd->hp_flags;
+       isrlink(&dcaisr[unit]);
+#ifdef KGDB
+       if (kgdb_dev == makedev(1, unit)) {
+               if (dcaconsole == unit)
+                       kgdb_dev = -1;  /* can't debug over console port */
+               else {
+                       (void) dcainit(unit);
+                       dcaconsole = -2; /* XXX */
+                       if (kgdb_debug_init) {
+                               printf("dca%d: kgdb waiting...", unit);
+                               /* trap into kgdb */
+                               asm("trap #15;");
+                               printf("connected.\n");
+                       } else
+                               printf("dca%d: kgdb enabled\n", unit);
+               }
+       }
+#endif
+       dca->dca_ic = IC_IE;
+       /*
+        * Need to reset baud rate, etc. of next print so reset dcaconsole.
+        * Also make sure console is always "hardwired"
+        */
+       if (unit == dcaconsole) {
+               dcaconsole = -1;
+               dcasoftCAR |= (1 << unit);
+       }
+       return (1);
+}
+
+dcaopen(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register int unit;
+       unit = UNIT(dev);
+       if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
+               return (ENXIO);
+       tp = &dca_tty[unit];
+       tp->t_oproc = dcastart;
+       tp->t_param = dcaparam;
+       tp->t_dev = dev;
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
+               dcaparam(tp, &tp->t_termios);
+               ttsetwater(tp);
+       } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+               return (EBUSY);
+       (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
+       if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
+               tp->t_state |= TS_CARR_ON;
+       (void) spltty();
+       while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
+              (tp->t_state & TS_CARR_ON) == 0) {
+               tp->t_state |= TS_WOPEN;
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       }
+       (void) spl0();
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+/*ARGSUSED*/
+dcaclose(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register struct dcadevice *dca;
+       register int unit;
+       unit = UNIT(dev);
+       dca = dca_addr[unit];
+       tp = &dca_tty[unit];
+       (*linesw[tp->t_line].l_close)(tp);
+       dca->dca_cfcr &= ~CFCR_SBREAK;
+#ifdef KGDB
+       /* do not disable interrupts if debugging */
+       if (kgdb_dev != makedev(1, unit))
+#endif
+       dca->dca_ier = 0;
+       if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 
+           (tp->t_state&TS_ISOPEN) == 0)
+               (void) dcamctl(dev, 0, DMSET);
+       ttyclose(tp);
+       return(0);
+}
+dcaread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp = &dca_tty[UNIT(dev)];
+       return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+dcawrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       int unit = UNIT(dev);
+       register struct tty *tp = &dca_tty[unit];
+       if (unit == dcaconsole && constty &&
+           (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN))
+               tp = constty;
+       return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+dcaintr(unit)
+       register int unit;
+{
+       register struct dcadevice *dca;
+       register int code;
+
+       dca = dca_addr[unit];
+       if ((dca->dca_ic & IC_IR) == 0)
+               return(0);
+       while (((code = dca->dca_iir) & IIR_NOPEND) == 0) {
+               code &= IIR_IMASK;
+               if (code == IIR_RLS)
+                       dcaeint(unit, dca);
+               else if (code == IIR_RXRDY)
+                       dcarint(unit, dca);
+               else if (code == IIR_TXRDY)
+                       dcaxint(unit, dca);
+               else
+                       dcamint(unit, dca);
+       }
+       return(1);
+}
+
+dcaeint(unit, dca)
+       register int unit;
+       register struct dcadevice *dca;
+{
+       register struct tty *tp;
+       register int stat, c;
+
+       tp = &dca_tty[unit];
+       stat = dca->dca_lsr;
+       c = dca->dca_data & 0xff;
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+#ifdef KGDB
+               /* we don't care about parity errors */
+               if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
+                   kgdb_dev == makedev(1, unit) && c == '!') {
+                       printf("kgdb trap from dca%d\n", unit);
+                       /* trap into kgdb */
+                       asm("trap #15;");
+               }
+#endif
+               return;
+       }
+       if (stat & (LSR_BI | LSR_FE))
+               c |= TTY_FE;
+       else if (stat & LSR_PE)
+               c |= TTY_PE;
+       else if (stat & LSR_OE)
+               log(LOG_WARNING, "dca%d: silo overflow\n", unit);
+       (*linesw[tp->t_line].l_rint)(c, tp);
+}
+
+dcarint(unit, dca)
+       int unit;
+       register struct dcadevice *dca;
+{
+       register struct tty *tp;
+       register int c;
+
+       tp = &dca_tty[unit];
+       c = dca->dca_data;
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+#ifdef KGDB
+               if (kgdb_dev == makedev(1, unit) && c == '!') {
+                       printf("kgdb trap from dca%d\n", unit);
+                       /* trap into kgdb */
+                       asm("trap #15;");
+               }
+#endif
+               return;
+       }
+       (*linesw[tp->t_line].l_rint)(c, tp);
+}
+
+/*ARGSUSED*/
+dcaxint(unit, dca)
+       int unit;
+       struct dcadevice *dca;
+{
+       register struct tty *tp;
+
+       tp = &dca_tty[unit];
+       tp->t_state &= ~TS_BUSY;
+       if (tp->t_state & TS_FLUSH)
+               tp->t_state &= ~TS_FLUSH;
+       if (tp->t_line)
+               (*linesw[tp->t_line].l_start)(tp);
+       else
+               dcastart(tp);
+}
+
+dcamint(unit, dca)
+       register int unit;
+       register struct dcadevice *dca;
+{
+       register struct tty *tp;
+       register int stat;
+
+       tp = &dca_tty[unit];
+       stat = dca->dca_msr;
+       if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) {
+               if (stat & MSR_DCD)
+                       (void) (*linesw[tp->t_line].l_modem)(tp, 1);
+               else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
+                       dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
+       }
+}
+
+dcaioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct tty *tp;
+       register int unit = UNIT(dev);
+       register struct dcadevice *dca;
+       register int error;
+       tp = &dca_tty[unit];
+       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+       if (error >= 0)
+               return (error);
+       error = ttioctl(tp, cmd, data, flag);
+       if (error >= 0)
+               return (error);
+
+       dca = dca_addr[unit];
+       switch (cmd) {
+
+       case TIOCSBRK:
+               dca->dca_cfcr |= CFCR_SBREAK;
+               break;
+
+       case TIOCCBRK:
+               dca->dca_cfcr &= ~CFCR_SBREAK;
+               break;
+
+       case TIOCSDTR:
+               (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
+               break;
+
+       case TIOCCDTR:
+               (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
+               break;
+
+       case TIOCMSET:
+               (void) dcamctl(dev, *(int *)data, DMSET);
+               break;
+
+       case TIOCMBIS:
+               (void) dcamctl(dev, *(int *)data, DMBIS);
+               break;
+
+       case TIOCMBIC:
+               (void) dcamctl(dev, *(int *)data, DMBIC);
+               break;
+
+       case TIOCMGET:
+               *(int *)data = dcamctl(dev, 0, DMGET);
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+dcaparam(tp, t)
+       register struct tty *tp;
+       register struct termios *t;
+{
+       register struct dcadevice *dca;
+       register int cfcr, cflag = t->c_cflag;
+       int unit = UNIT(tp->t_dev);
+       int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
+       /* check requested parameters */
+        if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+                return(EINVAL);
+        /* and copy to tty */
+        tp->t_ispeed = t->c_ispeed;
+        tp->t_ospeed = t->c_ospeed;
+        tp->t_cflag = cflag;
+
+       dca = dca_addr[unit];
+       dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
+       if (ospeed == 0) {
+               (void) dcamctl(unit, 0, DMSET); /* hang up line */
+               return(0);
+       }
+       dca->dca_cfcr |= CFCR_DLAB;
+       dca->dca_data = ospeed & 0xFF;
+       dca->dca_ier = ospeed >> 8;
+       switch (cflag&CSIZE) {
+       case CS5:
+               cfcr = CFCR_5BITS; break;
+       case CS6:
+               cfcr = CFCR_6BITS; break;
+       case CS7:
+               cfcr = CFCR_7BITS; break;
+       case CS8:
+               cfcr = CFCR_8BITS; break;
+       }
+       if (cflag&PARENB) {
+               cfcr |= CFCR_PENAB;
+               if ((cflag&PARODD) == 0)
+                       cfcr |= CFCR_PEVEN;
+       }
+       if (cflag&CSTOPB)
+               cfcr |= CFCR_STOPB;
+       dca->dca_cfcr = cfcr;
+       return(0);
+}
+dcastart(tp)
+       register struct tty *tp;
+{
+       register struct dcadevice *dca;
+       int s, unit, c;
+       unit = UNIT(tp->t_dev);
+       dca = dca_addr[unit];
+       s = spltty();
+       if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+               goto out;
+       if (tp->t_outq.c_cc <= tp->t_lowat) {
+               if (tp->t_state&TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup((caddr_t)&tp->t_outq);
+               }
+               if (tp->t_wsel) {
+                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+                       tp->t_wsel = 0;
+                       tp->t_state &= ~TS_WCOLL;
+               }
+       }
+       if (tp->t_outq.c_cc == 0)
+               goto out;
+       c = getc(&tp->t_outq);
+       tp->t_state |= TS_BUSY;
+       dca->dca_data = c;
+out:
+       splx(s);
+}
+/*
+ * Stop output on a line.
+ */
+/*ARGSUSED*/
+dcastop(tp, flag)
+       register struct tty *tp;
+{
+       register int s;
+
+       s = spltty();
+       if (tp->t_state & TS_BUSY) {
+               if ((tp->t_state&TS_TTSTOP)==0)
+                       tp->t_state |= TS_FLUSH;
+       }
+       splx(s);
+}
+dcamctl(dev, bits, how)
+       dev_t dev;
+       int bits, how;
+{
+       register struct dcadevice *dca;
+       register int unit;
+       int s;
+
+       unit = UNIT(dev);
+       dca = dca_addr[unit];
+       s = spltty();
+       switch (how) {
+
+       case DMSET:
+               dca->dca_mcr = bits;
+               break;
+
+       case DMBIS:
+               dca->dca_mcr |= bits;
+               break;
+
+       case DMBIC:
+               dca->dca_mcr &= ~bits;
+               break;
+
+       case DMGET:
+               bits = dca->dca_msr;
+               break;
+       }
+       (void) splx(s);
+       return(bits);
+}
+
+/*
+ * Following are all routines needed for DCA to act as console
+ */
+#include "machine/cons.h"
+
+dcacnprobe(cp)
+       struct consdev *cp;
+{
+       int unit, i;
+       extern int dcaopen();
+
+       /* XXX: ick */
+       unit = CONUNIT;
+       dca_addr[CONUNIT] = CONADDR;
+
+       /* make sure hardware exists */
+       if (badaddr((short *)dca_addr[unit])) {
+               cp->cn_pri = CN_DEAD;
+               return;
+       }
+
+       /* locate the major number */
+       for (i = 0; i < nchrdev; i++)
+               if (cdevsw[i].d_open == dcaopen)
+                       break;
+
+       /* initialize required fields */
+       cp->cn_dev = makedev(i, unit);
+       cp->cn_tp = &dca_tty[unit];
+       switch (dca_addr[unit]->dca_irid) {
+       case DCAID0:
+       case DCAID1:
+               cp->cn_pri = CN_NORMAL;
+               break;
+       case DCAREMID0:
+       case DCAREMID1:
+               cp->cn_pri = CN_REMOTE;
+               break;
+       default:
+               cp->cn_pri = CN_DEAD;
+               break;
+       }
+}
+
+dcacninit(cp)
+       struct consdev *cp;
+{
+       int unit = UNIT(cp->cn_dev);
+
+       dcainit(unit);
+       dcaconsole = unit;
+}
+
+dcainit(unit)
+       int unit;
+{
+       register struct dcadevice *dca;
+       int s, rate;
+       short stat;
+
+#ifdef lint
+       stat = unit; if (stat) return;
+#endif
+       dca = dca_addr[unit];
+       s = splhigh();
+       dca->dca_irid = 0xFF;
+       DELAY(100);
+       dca->dca_ic = IC_IE;
+       dca->dca_cfcr = CFCR_DLAB;
+       rate = ttspeedtab(dcadefaultrate, dcaspeedtab);
+       dca->dca_data = rate & 0xFF;
+       dca->dca_ier = rate >> 8;
+       dca->dca_cfcr = CFCR_8BITS;
+       dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
+       stat = dca->dca_iir;
+       splx(s);
+}
+
+dcacngetc(dev)
+{
+       register struct dcadevice *dca = dca_addr[UNIT(dev)];
+       short stat;
+       int c, s;
+
+#ifdef lint
+       stat = dev; if (stat) return(0);
+#endif
+       s = splhigh();
+       while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
+               ;
+       c = dca->dca_data;
+       stat = dca->dca_iir;
+       splx(s);
+       return(c);
+}
+
+/*
+ * Console kernel output character routine.
+ */
+dcacnputc(dev, c)
+       dev_t dev;
+       register int c;
+{
+       register struct dcadevice *dca = dca_addr[UNIT(dev)];
+       register int timo;
+       short stat;
+       int s = splhigh();
+
+#ifdef lint
+       stat = dev; if (stat) return;
+#endif
+       if (dcaconsole == -1) {
+               (void) dcainit(UNIT(dev));
+               dcaconsole = UNIT(dev);
+       }
+       /* wait for any pending transmission to finish */
+       timo = 50000;
+       while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
+               ;
+       dca->dca_data = c;
+       /* wait for this transmission to complete */
+       timo = 1500000;
+       while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
+               ;
+       /* clear any interrupts generated by this transmission */
+       stat = dca->dca_iir;
+       splx(s);
+}
+#endif
diff --git a/usr/src/sys/hp/dev/dcareg.h b/usr/src/sys/hp/dev/dcareg.h
new file mode 100644 (file)
index 0000000..25a1089
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)dcareg.h    7.1 (Berkeley) %G%
+ */
+
+struct dcadevice {
+       u_char  dca_pad0;
+       volatile u_char dca_irid;
+       volatile short  dca_ic;
+       volatile short  dca_ocbrc;
+       volatile short  dca_lcsm;
+       short   dca_pad1[4];
+       u_char  dca_pad2;
+       volatile u_char dca_data;
+       volatile short  dca_ier;
+       volatile short  dca_iir;
+       volatile short  dca_cfcr;
+       volatile short  dca_mcr;
+       volatile short  dca_lsr;
+       u_char  dca_pad3;
+       volatile u_char dca_msr;
+};
+
+/* interface reset/id */
+#define        DCAID0          0x02
+#define DCAREMID0      0x82
+#define        DCAID1          0x42
+#define DCAREMID1      0xC2
+
+/* interrupt control */
+#define        DCAIPL(x)       ((((x) >> 4) & 3) + 3)
+#define        IC_IR           0x40
+#define        IC_IE           0x80
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define        DCABRD(x)       (153600 / (x))
+
+/* interrupt enable register */
+#define        IER_ERXRDY      0x1
+#define        IER_ETXRDY      0x2
+#define        IER_ERLS        0x4
+#define        IER_EMSC        0x8
+
+/* interrupt identification register */
+#define        IIR_NOPEND      0x1
+#define        IIR_IMASK       0x6
+#define        IIR_RLS         6
+#define        IIR_RXRDY       4
+#define        IIR_TXRDY       2
+#define        IIR_MLSC        0
+
+/* character format control register */
+#define        CFCR_DLAB       0x80
+#define        CFCR_SBREAK     0x40
+#define        CFCR_PZERO      0x30
+#define        CFCR_PONE       0x20
+#define        CFCR_PEVEN      0x10
+#define        CFCR_PODD       0x00
+#define        CFCR_PENAB      0x08
+#define        CFCR_STOPB      0x04
+#define        CFCR_8BITS      0x03
+#define        CFCR_7BITS      0x02
+#define        CFCR_6BITS      0x01
+#define        CFCR_5BITS      0x00
+
+/* modem control register */
+#define        MCR_LOOPBACK    0x10
+#define        MCR_SRTS        0x08
+#define        MCR_DRS         0x04
+#define        MCR_RTS         0x02
+#define        MCR_DTR         0x01
+
+/* line status register */
+#define        LSR_TSRE        0x40
+#define        LSR_TXRDY       0x20
+#define        LSR_BI          0x10
+#define        LSR_FE          0x08
+#define        LSR_PE          0x04
+#define        LSR_OE          0x02
+#define        LSR_RXRDY       0x01
+
+/* modem status register */
+#define        MSR_DCD         0x80
+#define        MSR_RI          0x40
+#define        MSR_DSR         0x20
+#define        MSR_CTS         0x10
+#define        MSR_CCD         0x08
+#define        MSR_TERI        0x04
+#define        MSR_DDSR        0x02
+#define        MSR_CCTS        0x01
+
+/*
+ * WARNING: Serial console is assumed to be at SC9
+ * and CONUNIT must be 0.
+ */
+#define CONADDR        ((struct dcadevice *)(IOV(EXTIOBASE + (9 * IOCARDSIZE))))
+#define CONUNIT        (0)
diff --git a/usr/src/sys/hp/dev/device.h b/usr/src/sys/hp/dev/device.h
new file mode 100644 (file)
index 0000000..ecbdfce
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)device.h    7.1 (Berkeley) %G%
+ */
+
+struct driver {
+       int     (*d_init)();
+       char    *d_name;
+       int     (*d_start)();
+       int     (*d_go)();
+       int     (*d_intr)();
+       int     (*d_done)();
+};
+
+struct hp_ctlr {
+       struct driver   *hp_driver;
+       int             hp_unit;
+       int             hp_alive;
+       char            *hp_addr;
+       int             hp_flags;
+       int             hp_ipl;
+};
+
+struct hp_device {
+       struct driver   *hp_driver;
+       struct driver   *hp_cdriver;
+       int             hp_unit;
+       int             hp_ctlr;
+       int             hp_slave;
+       char            *hp_addr;
+       int             hp_dk;
+       int             hp_flags;
+       int             hp_alive;
+       int             hp_ipl;
+};
+
+struct devqueue {
+       struct  devqueue *dq_forw;
+       struct  devqueue *dq_back;
+       int     dq_ctlr;
+       int     dq_unit;
+       int     dq_slave;
+       struct  driver *dq_driver;
+};
+
+struct hp_hw {
+       char    *hw_addr;       /* physical address of registers */
+       short   hw_sc;          /* select code (if applicable) */
+       short   hw_type;        /* type (defined below) */
+       short   hw_id;          /* HW returned id */
+       short   hw_id2;         /* secondary HW id (displays) */
+       char    *hw_name;       /* HP product name */
+};
+
+#define        MAX_CTLR        16      /* Totally arbitrary */
+#define        MAXSLAVES       8       /* Currently the HPIB limit */
+
+#define        WILD_CARD_CTLR  0
+
+/* A controller is a card which can have one or more slaves attached */
+#define        CONTROLLER      0x10
+#define        HPIB            0x16
+#define        SCSI            0x17
+#define        VME             0x18
+#define        FLINK           0x19
+
+/* Slaves are devices which attach to controllers, e.g. disks, tapes */
+#define        RD              0x2a
+#define        PPI             0x2b
+#define        CT              0x2c
+
+/* These are not controllers, but may have their own HPIB address */
+#define        BITMAP          0x01
+#define        NET             0x02
+#define        COMM            0x03
+#define        FPA             0x04
+#define        MISC            0x05
+#define KEYBOARD       0x06
+
+#ifdef KERNEL
+extern struct hp_ctlr  hp_cinit[];
+extern struct hp_device        hp_dinit[];
+extern struct hp_hw    sc_table[];
+#endif
diff --git a/usr/src/sys/hp/dev/grf.c b/usr/src/sys/hp/dev/grf.c
new file mode 100644 (file)
index 0000000..8d405dc
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf.c 1.28 89/08/14$
+ *
+ *     @(#)grf.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ * Graphics display driver for the HP300.
+ * This is the hardware-independent portion of the driver.
+ * Hardware access is through the grfdev routines below.
+ */
+
+#include "grf.h"
+#if NGRF > 0
+
+#include "param.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "file.h"
+#include "mapmem.h"
+#include "malloc.h"
+
+#include "device.h"
+#include "grfioctl.h"
+#include "grfvar.h"
+
+#include "machine/cpu.h"
+
+#ifdef HPUXCOMPAT
+#include "../hpux/hpux.h"
+#endif
+
+#include "ite.h"
+#if NITE == 0
+#define        iteon(u,f)
+#define        iteoff(u,f)
+#endif
+
+int    grfprobe();
+int    tc_init(), tc_mode();
+int    gb_init(), gb_mode();
+int    rb_init(), rb_mode();
+int    dv_init(), dv_mode();
+
+struct grfdev grfdev[] = {
+       GID_TOPCAT,     GRFBOBCAT,      tc_init,        tc_mode,
+       "topcat",
+       GID_GATORBOX,   GRFGATOR,       gb_init,        gb_mode,
+       "gatorbox",
+       GID_RENAISSANCE,GRFRBOX,        rb_init,        rb_mode,
+       "renaissance",
+       GID_LRCATSEYE,  GRFCATSEYE,     tc_init,        tc_mode,
+       "lo-res catseye",
+       GID_HRCCATSEYE, GRFCATSEYE,     tc_init,        tc_mode,
+       "hi-res catseye",
+       GID_HRMCATSEYE, GRFCATSEYE,     tc_init,        tc_mode,
+       "hi-res catseye",
+       GID_DAVINCI,    GRFDAVINCI,     dv_init,        dv_mode,
+       "davinci",
+};
+int    ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]);
+
+struct driver grfdriver = { grfprobe, "grf" };
+struct grf_softc grf_softc[NGRF];
+
+#ifdef MAPMEM
+int grfexit();
+struct mapmemops grfops = { (int (*)())0, (int (*)())0, grfexit, grfexit };
+#ifdef HPUXCOMPAT
+struct mapmemops grflckops = { (int (*)())0, (int (*)())0, grfexit, grfexit };
+struct mapmemops grfiomops = { (int (*)())0, (int (*)())0, grfexit, grfexit };
+#endif
+#endif
+
+#ifdef DEBUG
+int grfdebug = 0;
+#define GDB_DEVNO      0x01
+#define GDB_MMAP       0x02
+#define GDB_IOMAP      0x04
+#define GDB_LOCK       0x08
+#endif
+
+/*
+ * XXX: called from ite console init routine.
+ * Does just what configure will do later but without printing anything.
+ */
+grfconfig()
+{
+       register caddr_t addr;
+       register struct hp_hw *hw;
+       register struct hp_device *hd, *nhd;
+
+       for (hw = sc_table; hw->hw_type; hw++) {
+               if (hw->hw_type != BITMAP)
+                       continue;
+               /*
+                * Found one, now match up with a logical unit number
+                */
+               nhd = NULL;             
+               addr = hw->hw_addr;
+               for (hd = hp_dinit; hd->hp_driver; hd++) {
+                       if (hd->hp_driver != &grfdriver || hd->hp_alive)
+                               continue;
+                       /*
+                        * Wildcarded.  If first, remember as possible match.
+                        */
+                       if (hd->hp_addr == NULL) {
+                               if (nhd == NULL)
+                                       nhd = hd;
+                               continue;
+                       }
+                       /*
+                        * Not wildcarded.
+                        * If exact match done searching, else keep looking.
+                        */
+                       if ((caddr_t)sctoaddr(hd->hp_addr) == addr) {
+                               nhd = hd;
+                               break;
+                       }
+               }
+               /*
+                * Found a match, initialize
+                */
+               if (nhd && grfinit(addr, nhd->hp_unit)) {
+                       nhd->hp_addr = addr;
+               }
+       }
+}
+
+/*
+ * Normal init routine called by configure() code
+ */
+grfprobe(hd)
+       struct hp_device *hd;
+{
+       struct grf_softc *gp = &grf_softc[hd->hp_unit];
+
+       if ((gp->g_flags & GF_ALIVE) == 0 &&
+           !grfinit(hd->hp_addr, hd->hp_unit))
+               return(0);
+       printf("grf%d: %d x %d ", hd->hp_unit,
+              gp->g_display.gd_dwidth, gp->g_display.gd_dheight);
+       if (gp->g_display.gd_colors == 2)
+               printf("monochrome");
+       else
+               printf("%d color", gp->g_display.gd_colors);
+       printf(" %s display\n", grfdev[gp->g_type].gd_desc);
+       return(1);
+}
+
+grfinit(addr, unit)
+       caddr_t addr;
+{
+       struct grf_softc *gp = &grf_softc[unit];
+       struct grfreg *gr;
+       register struct grfdev *gd;
+
+       gr = (struct grfreg *) addr;
+       if (gr->gr_id != GRFHWID)
+               return(0);
+       for (gd = grfdev; gd < &grfdev[ngrfdev]; gd++)
+               if (gd->gd_hardid == gr->gr_id2)
+                       break;
+       if (gd < &grfdev[ngrfdev] && (*gd->gd_init)(gp, addr)) {
+               gp->g_display.gd_id = gd->gd_softid;
+               gp->g_type = gd - grfdev;
+               gp->g_flags = GF_ALIVE;
+               return(1);
+       }
+       return(0);
+}
+
+/*ARGSUSED*/
+grfopen(dev, flags)
+       dev_t dev;
+{
+       int unit = GRFUNIT(dev);
+       register struct grf_softc *gp = &grf_softc[unit];
+       int error = 0;
+
+       if (unit >= NGRF || (gp->g_flags & GF_ALIVE) == 0)
+               return(ENXIO);
+       if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE))
+               return(EBUSY);
+#ifdef HPUXCOMPAT
+       /*
+        * XXX: cannot handle both HPUX and BSD processes at the same time
+        */
+       if (u.u_procp->p_flag & SHPUX)
+               if (gp->g_flags & GF_BSDOPEN)
+                       return(EBUSY);
+               else
+                       gp->g_flags |= GF_HPUXOPEN;
+       else
+               if (gp->g_flags & GF_HPUXOPEN)
+                       return(EBUSY);
+               else
+                       gp->g_flags |= GF_BSDOPEN;
+#endif
+       /*
+        * First open.
+        * XXX: always put in graphics mode.
+        */
+       error = 0;
+       if ((gp->g_flags & GF_OPEN) == 0) {
+               gp->g_flags |= GF_OPEN;
+               error = grfon(dev);
+       }
+       return(error);
+}
+
+/*ARGSUSED*/
+grfclose(dev, flags)
+       dev_t dev;
+{
+       register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+
+       (void) grfoff(dev);
+       (void) grfunlock(gp);
+       gp->g_flags &= GF_ALIVE;
+       return(0);
+}
+
+/*ARGSUSED*/
+grfioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+       int error;
+
+#ifdef HPUXCOMPAT
+       if (u.u_procp->p_flag & SHPUX)
+               return(hpuxgrfioctl(dev, cmd, data, flag));
+#endif
+       error = 0;
+       switch (cmd) {
+
+       /* XXX: compatibility hack */
+       case OGRFIOCGINFO:
+               bcopy((caddr_t)&gp->g_display, data, sizeof(struct ogrfinfo));
+               break;
+
+       case GRFIOCGINFO:
+               bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo));
+               break;
+
+       case GRFIOCON:
+               error = grfon(dev);
+               break;
+
+       case GRFIOCOFF:
+               error = grfoff(dev);
+               break;
+
+#ifdef MAPMEM
+       case GRFIOCMAP:
+               error = grfmmap(dev, (caddr_t *)data);
+               break;
+
+       case GRFIOCUNMAP:
+               error = grfunmmap(dev, *(caddr_t *)data);
+               break;
+#endif
+
+       default:
+               error = EINVAL;
+               break;
+
+       }
+       return(error);
+}
+
+/*ARGSUSED*/
+grfselect(dev, rw)
+       dev_t dev;
+{
+       if (rw == FREAD)
+               return(0);
+       return(1);
+}
+
+grflock(gp, block)
+       register struct grf_softc *gp;
+       int block;
+{
+#ifdef DEBUG
+       if (grfdebug & GDB_LOCK)
+               printf("grflock(%d): dev %x flags %x lockpid %x\n",
+                      u.u_procp->p_pid, gp-grf_softc, gp->g_flags,
+                      gp->g_lockp ? gp->g_lockp->p_pid : -1);
+#endif
+#ifdef HPUXCOMPAT
+       if (gp->g_pid) {
+#ifdef DEBUG
+               if (grfdebug & GDB_LOCK)
+                       printf("  lock[0] %d lockslot %d lock[lockslot] %d\n",
+                              gp->g_locks[0], gp->g_lockpslot,
+                              gp->g_locks[gp->g_lockpslot]);
+#endif
+               gp->g_locks[0] = 0;
+               if (gp->g_locks[gp->g_lockpslot] == 0) {
+                       gp->g_lockp = NULL;
+                       gp->g_lockpslot = 0;
+               }
+       }
+#endif
+       if (gp->g_lockp) {
+               if (gp->g_lockp == u.u_procp)
+                       return(EBUSY);
+               if (!block)
+                       return(EAGAIN);
+               do {
+                       gp->g_flags |= GF_WANTED;
+                       sleep((caddr_t)&gp->g_flags, PZERO+1);
+               } while (gp->g_lockp);
+       }
+       gp->g_lockp = u.u_procp;
+#ifdef HPUXCOMPAT
+       if (gp->g_pid) {
+               int slot = grffindpid(gp);
+#ifdef DEBUG
+               if (grfdebug & GDB_LOCK)
+                       printf("  slot %d\n", slot);
+#endif
+               gp->g_lockpslot = gp->g_locks[0] = slot;
+               gp->g_locks[slot] = 1;
+       }
+#endif
+       return(0);
+}
+
+grfunlock(gp)
+       register struct grf_softc *gp;
+{
+#ifdef DEBUG
+       if (grfdebug & GDB_LOCK)
+               printf("grfunlock(%d): dev %x flags %x lockpid %d\n",
+                      u.u_procp->p_pid, gp-grf_softc, gp->g_flags,
+                      gp->g_lockp ? gp->g_lockp->p_pid : -1);
+#endif
+       if (gp->g_lockp != u.u_procp)
+               return(EBUSY);
+#ifdef HPUXCOMPAT
+       if (gp->g_pid) {
+#ifdef DEBUG
+               if (grfdebug & GDB_LOCK)
+                       printf("  lock[0] %d lockslot %d lock[lockslot] %d\n",
+                              gp->g_locks[0], gp->g_lockpslot,
+                              gp->g_locks[gp->g_lockpslot]);
+#endif
+               gp->g_locks[gp->g_lockpslot] = gp->g_locks[0] = 0;
+               gp->g_lockpslot = 0;
+       }
+#endif
+       if (gp->g_flags & GF_WANTED) {
+               wakeup((caddr_t)&gp->g_flags); 
+               gp->g_flags &= ~GF_WANTED;
+       }
+       gp->g_lockp = NULL;
+       return(0);
+}
+
+/*ARGSUSED*/
+grfmap(dev, off, prot)
+       dev_t dev;
+{
+       return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
+}
+
+#ifdef HPUXCOMPAT
+
+/*ARGSUSED*/
+hpuxgrfioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+       int error;
+
+       error = 0;
+       switch (cmd) {
+
+       case GCID:
+               *(int *)data = gp->g_display.gd_id;
+               break;
+
+       case GCON:
+               error = grfon(dev);
+               break;
+
+       case GCOFF:
+               error = grfoff(dev);
+               break;
+
+       case GCLOCK:
+               error = grflock(gp, 1);
+               break;
+
+       case GCUNLOCK:
+               error = grfunlock(gp);
+               break;
+
+       case GCAON:
+       case GCAOFF:
+               break;
+
+       /* GCSTATIC is implied by our implementation */
+       case GCSTATIC_CMAP:
+       case GCVARIABLE_CMAP:
+               break;
+
+#ifdef MAPMEM
+       /* map in control regs and frame buffer */
+       case GCMAP:
+               error = grfmmap(dev, (caddr_t *)data);
+               break;
+
+       case GCUNMAP:
+               error = grfunmmap(dev, *(caddr_t *)data);
+               /* XXX: HP-UX uses GCUNMAP to get rid of GCSLOT memory */
+               if (error)
+                       error = grflckunmmap(dev, *(caddr_t *)data);
+               break;
+
+       case GCSLOT:
+       {
+               struct grf_slot *sp = (struct grf_slot *)data;
+
+               sp->slot = grffindpid(gp);
+               if (sp->slot)
+                       error = grflckmmap(dev, (caddr_t *)&sp->addr);
+               else
+                       error = EINVAL;         /* XXX */
+               break;
+       }
+
+       /*
+        * XXX: only used right now to map in rbox control registers
+        * Will be replaced in the future with a real IOMAP interface.
+        */
+       case IOMAPMAP:
+               error = iommap(dev, (caddr_t *)data);
+               if (!error)
+                       u.u_r.r_val1 = *(int *)data;    /* XXX: this sux */
+               break;
+
+       case IOMAPUNMAP:
+               error = iounmmap(dev, *(caddr_t *)data);
+               break;
+#endif
+
+       default:
+               error = EINVAL;
+               break;
+       }
+       return(error);
+}
+
+#endif
+
+grfon(dev)
+       dev_t dev;
+{
+       int unit = GRFUNIT(dev);
+       struct grf_softc *gp = &grf_softc[unit];
+
+       /*
+        * XXX: iteoff call relies on devices being in same order
+        * as ITEs and the fact that iteoff only uses the minor part
+        * of the dev arg.
+        */
+       iteoff(unit, 3);
+       return((*grfdev[gp->g_type].gd_mode)
+                       (gp, (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON));
+}
+
+grfoff(dev)
+       dev_t dev;
+{
+       int unit = GRFUNIT(dev);
+       struct grf_softc *gp = &grf_softc[unit];
+       int error;
+
+#ifdef MAPMEM
+       (void) grfunmmap(dev, (caddr_t)0);
+#endif
+       error = (*grfdev[gp->g_type].gd_mode)
+                       (gp, (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF);
+       /* XXX: see comment for iteoff above */
+       iteon(unit, 2);
+       return(error);
+}
+
+grfaddr(gp, off)
+       struct grf_softc *gp;
+       register int off;
+{
+#ifdef MAPMEM
+       register struct grfinfo *gi = &gp->g_display;
+
+       /* control registers */
+       if (off >= 0 && off < gi->gd_regsize)
+               return(((u_int)gi->gd_regaddr + off) >> PGSHIFT);
+
+       /* frame buffer */
+       if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) {
+               off -= gi->gd_regsize;
+               return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT);
+       }
+#endif
+       /* bogus */
+       return(-1);
+}
+
+#ifdef HPUXCOMPAT
+/*
+ * Convert a BSD style minor devno to HPUX style.
+ * We cannot just create HPUX style nodes as they require 24 bits
+ * of minor device number and we only have 8.
+ * XXX: This may give the wrong result for remote stats of other
+ * machines where device 10 exists.
+ */
+grfdevno(dev)
+       dev_t dev;
+{
+       int unit = GRFUNIT(dev);
+       struct grf_softc *gp = &grf_softc[unit];
+       int newdev;
+
+       if (unit >= NGRF || (gp->g_flags&GF_ALIVE) == 0)
+               return(bsdtohpuxdev(dev));
+       /* magic major number */
+       newdev = 12 << 24;
+       /* now construct minor number */
+#if defined(HP360) || defined(HP370)
+       if (gp->g_display.gd_regaddr == (caddr_t)DIOIIBASE)
+               newdev |= 0x840200;
+       else
+#endif
+       if (gp->g_display.gd_regaddr != (caddr_t)GRFIADDR)
+               newdev |= ((u_int)gp->g_display.gd_regaddr-EXTIOBASE) | 0x200;
+       if (dev & GRFIMDEV)
+               newdev |= 0x02;
+       else if (dev & GRFOVDEV)
+               newdev |= 0x01;
+#ifdef DEBUG
+       if (grfdebug & GDB_DEVNO)
+               printf("grfdevno: dev %x newdev %x\n", dev, newdev);
+#endif
+       return(newdev);
+}
+#endif
+
+#ifdef MAPMEM
+grfmapin(mp, off)
+       struct mapmem *mp;
+{
+       return(grfaddr(&grf_softc[GRFUNIT(mp->mm_id)], off));
+}
+
+grfmmap(dev, addrp)
+       dev_t dev;
+       caddr_t *addrp;
+{
+       struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+       register struct mapmem *mp;
+       int len, grfmapin();
+
+#ifdef DEBUG
+       if (grfdebug & GDB_MMAP)
+               printf("grfmmap(%d): addr %x\n", u.u_procp->p_pid, *addrp);
+#endif
+       len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
+       mp = mmalloc(minor(dev), addrp, len, MM_RW|MM_CI|MM_NOCORE, &grfops);
+       if (mp == MMNIL)
+               return(u.u_error);
+       if (!mmmapin(mp, grfmapin)) {
+               mmfree(mp);
+               return(u.u_error);
+       }
+       return(0);
+}
+
+grfunmmap(dev, addr)
+       dev_t dev;
+       caddr_t addr;
+{
+       register struct mapmem *mp, **mpp;
+       int found, unit = minor(dev);
+
+#ifdef DEBUG
+       if (grfdebug & GDB_MMAP)
+               printf("grfunmmap(%d): id %d addr %x\n",
+                      u.u_procp->p_pid, unit, addr);
+#endif
+       found = 0;
+       mpp = &u.u_mmap;
+       for (mp = *mpp; mp; mp = *mpp) {
+               if (mp->mm_ops != &grfops || mp->mm_id != unit) {
+                       mpp = &mp->mm_next;
+                       continue;
+               }
+               if (addr &&
+                   (addr < mp->mm_uva || addr >= mp->mm_uva+mp->mm_size)) {
+                       mpp = &mp->mm_next;
+                       continue;
+               }
+               grfexit(mp);
+               found++;
+       }
+       return(found ? 0 : EINVAL);
+}
+
+grfexit(mp)
+       struct mapmem *mp;
+{
+       struct grf_softc *gp = &grf_softc[GRFUNIT(mp->mm_id)];
+
+#ifdef DEBUG
+       if (grfdebug & GDB_MMAP)
+               printf("grfexit(%d): id %d %x@%x\n",
+                      u.u_procp->p_pid, mp->mm_id, mp->mm_size, mp->mm_uva);
+#endif
+       (void) grfunlock(gp);
+#ifdef HPUXCOMPAT
+       grfrmpid(gp);
+#endif
+       mmmapout(mp);
+       mmfree(mp);
+}
+
+#ifdef HPUXCOMPAT
+iommap(dev, addrp)
+       dev_t dev;
+       caddr_t *addrp;
+{
+       struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+       register struct mapmem *mp;
+       int len, grfmapin();
+
+#ifdef DEBUG
+       if (grfdebug & (GDB_MMAP|GDB_IOMAP))
+               printf("iommap(%d): addr %x\n", u.u_procp->p_pid, *addrp);
+#endif
+       len = gp->g_display.gd_regsize;
+       mp = mmalloc(minor(dev), addrp, len, MM_RW|MM_CI|MM_NOCORE, &grfiomops);
+       if (mp == MMNIL)
+               return(u.u_error);
+       if (!mmmapin(mp, grfmapin)) {
+               mmfree(mp);
+               return(u.u_error);
+       }
+       return(0);
+}
+
+iounmmap(dev, addr)
+       dev_t dev;
+       caddr_t addr;
+{
+       struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+       register struct mapmem *mp, **mpp;
+       int found, len, unit = minor(dev);
+
+#ifdef DEBUG
+       if (grfdebug & (GDB_MMAP|GDB_IOMAP))
+               printf("iounmmap(%d): id %d addr %x\n",
+                      u.u_procp->p_pid, unit, addr);
+#endif
+       found = 0;
+       len = gp->g_display.gd_regsize;
+       mpp = &u.u_mmap;
+       for (mp = *mpp; mp; mp = *mpp) {
+               if (mp->mm_ops != &grfiomops || mp->mm_id != unit) {
+                       mpp = &mp->mm_next;
+                       continue;
+               }
+               if (addr &&
+                   (addr < mp->mm_uva || addr >= mp->mm_uva+mp->mm_size ||
+                   len != mp->mm_size)) {
+                       mpp = &mp->mm_next;
+                       continue;
+               }
+               grfexit(mp);
+               found++;
+       }
+       return(found ? 0 : EINVAL);
+}
+
+/*
+ * Processes involved in framebuffer mapping via GCSLOT are recorded in
+ * an array of pids.  The first element is used to record the last slot used
+ * (for faster lookups).  The remaining elements record up to GRFMAXLCK-1
+ * process ids.  Returns a slot number between 1 and GRFMAXLCK or 0 if no
+ * slot is available. 
+ */
+grffindpid(gp)
+       struct grf_softc *gp;
+{
+       register short pid, *sp;
+       register int i, limit;
+       int ni;
+
+       if (gp->g_pid == NULL) {
+               gp->g_pid = (short *)
+                       malloc(GRFMAXLCK * sizeof(short), M_DEVBUF, M_WAITOK);
+               bzero((caddr_t)gp->g_pid, GRFMAXLCK * sizeof(short));
+       }
+       pid = u.u_procp->p_pid;
+       ni = limit = gp->g_pid[0];
+       for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) {
+               if (*sp == pid)
+                       goto done;
+               if (*sp == 0)
+                       ni = i;
+       }
+       i = ni;
+       if (i < limit) {
+               gp->g_pid[i] = pid;
+               goto done;
+       }
+       if (++i == GRFMAXLCK)
+               return(0);
+       gp->g_pid[0] = i;
+       gp->g_pid[i] = pid;
+done:
+#ifdef DEBUG
+       if (grfdebug & GDB_LOCK)
+               printf("grffindpid(%d): slot %d of %d\n",
+                      pid, i, gp->g_pid[0]);
+#endif
+       return(i);
+}
+
+grfrmpid(gp)
+       struct grf_softc *gp;
+{
+       register short pid, *sp;
+       register int limit, i;
+       int mi;
+
+       if (gp->g_pid == NULL || (limit = gp->g_pid[0]) == 0)
+               return;
+       pid = u.u_procp->p_pid;
+       limit = gp->g_pid[0];
+       mi = 0;
+       for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) {
+               if (*sp == pid)
+                       *sp = 0;
+               else if (*sp)
+                       mi = i;
+       }
+       i = mi;
+       if (i < limit)
+               gp->g_pid[0] = i;
+#ifdef DEBUG
+       if (grfdebug & GDB_LOCK)
+               printf("grfrmpid(%d): slot %d of %d\n",
+                      pid, sp-gp->g_pid, gp->g_pid[0]);
+#endif
+}
+
+/*ARGSUSED*/
+grflckmapin(mp, off)
+       struct mapmem *mp;
+{
+       u_int pa = kvtop((u_int)grf_softc[GRFUNIT(mp->mm_id)].g_locks);
+
+#ifdef DEBUG
+       if (grfdebug & GDB_LOCK)
+               printf("grflckmapin(%d): va %x pa %x\n", u.u_procp->p_pid,
+                      grf_softc[GRFUNIT(mp->mm_id)].g_locks, pa);
+#endif
+       return(pa >> PGSHIFT);
+}
+
+grflckmmap(dev, addrp)
+       dev_t dev;
+       caddr_t *addrp;
+{
+       struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
+       register struct mapmem *mp;
+       int grflckmapin();
+
+#ifdef DEBUG
+       if (grfdebug & (GDB_MMAP|GDB_LOCK))
+               printf("grflckmmap(%d): addr %x\n",
+                      u.u_procp->p_pid, *addrp);
+#endif
+       if (gp->g_locks == NULL) {
+               gp->g_locks = (u_char *) cialloc(NBPG);
+               if (gp->g_locks == NULL)
+                       return(ENOMEM);
+       }
+       mp = mmalloc(minor(dev), addrp, NBPG, MM_RW|MM_CI, &grflckops);
+       if (mp == MMNIL)
+               return(u.u_error);
+       if (!mmmapin(mp, grflckmapin)) {
+               mmfree(mp);
+               return(u.u_error);
+       }
+       return(0);
+}
+
+grflckunmmap(dev, addr)
+       dev_t dev;
+       caddr_t addr;
+{
+       register struct mapmem *mp;
+       int unit = minor(dev);
+
+#ifdef DEBUG
+       if (grfdebug & (GDB_MMAP|GDB_LOCK))
+               printf("grflckunmmap(%d): id %d addr %x\n",
+                      u.u_procp->p_pid, unit, addr);
+#endif
+       for (mp = u.u_mmap; mp; mp = mp->mm_next)
+               if (mp->mm_ops == &grflckops && mp->mm_id == unit &&
+                   mp->mm_uva == addr) {
+                       grfexit(mp);
+                       return(0);
+               }
+       return(EINVAL);
+}
+#endif /* HPUXCOMPAT */
+#endif /* MAPMEM */
+#endif /* NGRF > 0 */
diff --git a/usr/src/sys/hp/dev/grfioctl.h b/usr/src/sys/hp/dev/grfioctl.h
new file mode 100644 (file)
index 0000000..083b73f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grfioctl.h 1.13 89/01/18$
+ *
+ *     @(#)grfioctl.h  7.1 (Berkeley) %G%
+ */
+
+struct grfinfo {
+       int     gd_id;                  /* HPUX identifier */
+       caddr_t gd_regaddr;             /* control registers physaddr */
+       int     gd_regsize;             /* control registers size */
+       caddr_t gd_fbaddr;              /* frame buffer physaddr */
+       int     gd_fbsize;              /* frame buffer size */
+       short   gd_colors;              /* number of colors */
+       short   gd_planes;              /* number of planes */
+/* new stuff */
+       int     gd_fbwidth;             /* frame buffer width */
+       int     gd_fbheight;            /* frame buffer height */
+       int     gd_dwidth;              /* displayed part width */
+       int     gd_dheight;             /* displayed part height */
+       int     gd_pad[6];              /* for future expansion */
+};
+
+/* types */
+#define GRFGATOR       8
+#define GRFBOBCAT      9
+#define        GRFCATSEYE      9
+#define GRFRBOX                10
+#define GRFDAVINCI     14
+
+/*
+ * HPUX ioctls (here for the benefit of the driver)
+ */
+struct grf_slot {
+       int     slot;
+       u_char  *addr;
+};
+
+#ifndef _IOH
+#define _IOH(x,y)      (IOC_IN|((x)<<8)|y)     /* IOC_IN is IOC_VOID */
+
+#define        GCID            _IOR('G', 0, int)
+#define        GCON            _IOH('G', 1)
+#define        GCOFF           _IOH('G', 2)
+#define        GCAON           _IOH('G', 3)
+#define        GCAOFF          _IOH('G', 4)
+#define        GCMAP           _IOWR('G', 5, int)
+#define        GCUNMAP         _IOWR('G', 6, int)
+#define        GCLOCK          _IOH('G', 7)
+#define        GCUNLOCK        _IOH('G', 8)
+#define        GCLOCK_MINIMUM  _IOH('G', 9)
+#define        GCUNLOCK_MINIMUM _IOH('G', 10)
+#define        GCSTATIC_CMAP   _IOH('G', 11)
+#define        GCVARIABLE_CMAP _IOH('G', 12)
+#define GCSLOT         _IOWR('G', 13, struct grf_slot)
+
+/* XXX: for now */
+#define        IOMAPID         _IOR('M',0,int) /* ??? */
+#define        IOMAPMAP        _IOWR('M',1,int)
+#define        IOMAPUNMAP      _IOWR('M',2,int)
+#endif
+
+/*
+ * BSD ioctls
+ */
+#define        GRFIOCGINFO     _IOR('G', 0, struct grfinfo) /* get info on device */
+#define        GRFIOCON        _IO('G', 1)             /* turn graphics on */
+#define        GRFIOCOFF       _IO('G', 2)             /* turn graphics off */
+#define GRFIOCMAP      _IOWR('G', 5, int)      /* map in regs+framebuffer */
+#define GRFIOCUNMAP    _IOW('G', 6, int)       /* unmap regs+framebuffer */
+
+/* compat - for old grfinfo structure */
+struct ogrfinfo { char oinfo[24]; };
+#define        OGRFIOCGINFO    _IOR('G', 0, struct ogrfinfo)
diff --git a/usr/src/sys/hp/dev/grfvar.h b/usr/src/sys/hp/dev/grfvar.h
new file mode 100644 (file)
index 0000000..0a03f89
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grfvar.h 1.8 89/01/18$
+ *
+ *     @(#)grfvar.h    7.1 (Berkeley) %G%
+ */
+
+#define GRFMAXLCK      256
+
+/* per display info */
+struct grf_softc {
+       int     g_flags;                /* software flags */
+       int     g_type;                 /* type of display */
+       struct  grfinfo g_display;      /* hardware description */
+       struct  proc *g_lockp;          /* process holding lock */
+       int     g_lockpslot;            /* g_pid entry of g_lockp */
+       u_char  *g_locks;               /* lock page associated with device */
+       short   *g_pid;                 /* array of pids with device open */
+};
+
+/* flags */
+#define        GF_ALIVE        0x01
+#define GF_OPEN                0x02
+#define GF_EXCLUDE     0x04
+#define GF_WANTED      0x08
+#define GF_BSDOPEN     0x10
+#define GF_HPUXOPEN    0x20
+
+/* display types - indices into grfdev */
+#define        GT_TOPCAT       0
+#define        GT_GATORBOX     1
+#define        GT_RENAISSANCE  2
+#define GT_LRCATSEYE   3
+#define GT_HRCCATSEYE  4
+#define GT_HRMCATSEYE  5
+#define GT_DAVINCI     6
+
+struct grfdev {
+       int     gd_hardid;      /* secondary id returned by hardware */
+       int     gd_softid;      /* id returned by HP-UX */
+       int     (*gd_init)();   /* boot time initialization */
+       int     (*gd_mode)();   /* misc functions */
+       char    *gd_desc;       /* text description */
+};
+
+/* hardware ids */
+#define GID_GATORBOX   1
+#define        GID_TOPCAT      2
+#define GID_RENAISSANCE        4
+#define GID_LRCATSEYE  5
+#define GID_HRCCATSEYE 6
+#define GID_HRMCATSEYE 7
+#define GID_DAVINCI    8
+
+/* software ids defined in grfioctl.h */
+
+/* requests to mode routine */
+#define GM_GRFON       1
+#define GM_GRFOFF      2
+#define GM_GRFOVON     3
+#define GM_GRFOVOFF    4
+
+struct grfreg {
+       char    gr_pad0;
+       u_char  gr_id;          /* +0x01 */
+       char    gr_pad1[0x13];
+       u_char  gr_id2;         /* +0x15 */
+       char    gr_pad2[0x47];
+       u_char  gr_fbomsb;      /* +0x5d */
+       char    gr_pad3;
+       u_char  gr_fbolsb;      /* +0x5f */
+};
+/* bitmapped display hardware id */
+#define GRFHWID                0x39
+
+/* internal bitmapped display address */
+#define GRFIADDR       0x560000
+
+/* minor device interpretation */
+#define GRFOVDEV       0x10    /* overlay planes */
+#define GRFIMDEV       0x20    /* images planes */
+#define GRFUNIT(d)     ((d) & 0x7)
+
+#ifdef KERNEL
+extern struct grf_softc grf_softc[];
+#endif
diff --git a/usr/src/sys/hp/dev/hil.c b/usr/src/sys/hp/dev/hil.c
new file mode 100644 (file)
index 0000000..39adf9c
--- /dev/null
@@ -0,0 +1,1786 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: hil.c 1.33 89/12/22$
+ *
+ *     @(#)hil.c       7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "file.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+#include "kernel.h"
+#include "mapmem.h"
+
+#include "hilreg.h"
+#include "hilioctl.h"
+#include "hilvar.h"
+#include "kbdmap.h"
+
+#include "machine/cpu.h"
+
+struct hilloop hil0;
+struct _hilbell default_bell = { BELLDUR, BELLFREQ };
+
+#ifdef MAPMEM
+int    hilqfork(), hilqvfork(), hilqexit();
+struct mapmemops hilqops = { hilqfork, hilqvfork, hilqexit, hilqexit };
+#endif
+
+#ifdef DEBUG
+int    hildebug = 0;
+#define HDB_FOLLOW     0x01
+#define HDB_MMAP       0x02
+#define HDB_MASK       0x04
+#define HDB_CONFIG     0x08
+#define HDB_KEYBOARD   0x10
+#define HDB_IDMODULE   0x20
+#define HDB_EVENTS     0x80
+#endif
+
+hilinit()
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register int i;
+
+       /*
+        * Initialize loop information
+        */
+       hilp->hl_addr = HILADDR;
+       hilp->hl_cmdending = FALSE;
+       hilp->hl_actdev = hilp->hl_cmddev = 0;
+       hilp->hl_cmddone = FALSE;
+       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+       hilp->hl_pollbp = hilp->hl_pollbuf;
+       hilp->hl_kbddev = 0;
+       hilp->hl_kbdlang = KBD_DEFAULT;
+       hilp->hl_kbdflags = 0;
+       /*
+        * Clear all queues and device associations with queues
+        */
+       for (i = 0; i < NHILQ; i++) {
+               hilp->hl_queue[i].hq_eventqueue = NULL;
+               hilp->hl_queue[i].hq_procp = NULL;
+               hilp->hl_queue[i].hq_devmask = 0;
+       }
+       for (i = 0; i < NHILD; i++)
+               hilp->hl_device[i].hd_qmask = 0;
+       hilp->hl_device[HILLOOPDEV].hd_flags = (HIL_ALIVE|HIL_PSEUDO);
+       /*
+        * Reset the loop hardware, and collect keyboard/id info
+        */
+       hilreset(hilp);
+       hilinfo(hilp);
+       kbdenable();
+}
+
+hilopen(dev, flags)
+       dev_t dev;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register struct hilloopdev *dptr;
+       u_char device = HILUNIT(dev);
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilopen(%d): device %x\n", u.u_procp->p_pid, device);
+#endif
+       
+       if ((hilp->hl_device[HILLOOPDEV].hd_flags & HIL_ALIVE) == 0)
+               return(ENXIO);
+
+       dptr = &hilp->hl_device[device];
+       if ((dptr->hd_flags & HIL_ALIVE) == 0)
+               return(ENODEV);
+
+       /*
+        * Pseudo-devices cannot be read, nothing more to do.
+        */
+       if (dptr->hd_flags & HIL_PSEUDO)
+               return(0);
+
+       /*
+        * Open semantics:
+        * 1.   Open devices have only one of HIL_READIN/HIL_QUEUEIN.
+        * 2.   HPUX processes always get read syscall interface and
+        *      must have exclusive use of the device.
+        * 3.   BSD processes default to shared queue interface.
+        *      Multiple processes can open the device.
+        */
+       if (u.u_procp->p_flag & SHPUX) {
+               if (dptr->hd_flags & (HIL_READIN|HIL_QUEUEIN))
+                       return(EBUSY);
+               dptr->hd_flags |= HIL_READIN;
+       } else {
+               if (dptr->hd_flags & HIL_READIN)
+                       return(EBUSY);
+               dptr->hd_flags |= HIL_QUEUEIN;
+       }
+       if (flags & FNDELAY)
+               dptr->hd_flags |= HIL_NOBLOCK;
+       /*
+        * It is safe to flush the read buffer as we are guarenteed
+        * that no one else is using it.
+        */
+       ndflush(&dptr->hd_queue, dptr->hd_queue.c_cc);
+
+       send_hil_cmd(hilp->hl_addr, HIL_INTON, NULL, 0, NULL);
+       /*
+        * Opened the keyboard, put in raw mode.
+        */
+       (void) splhil();
+       if (device == hilp->hl_kbddev) {
+               u_char mask = 0;
+               send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &mask, 1, NULL);
+               hilp->hl_kbdflags |= KBD_RAW;
+#ifdef DEBUG
+               if (hildebug & HDB_KEYBOARD)
+                       printf("hilopen: keyboard %d raw\n", hilp->hl_kbddev);
+#endif
+       }
+       (void) spl0();
+       return (0);
+}
+
+/* ARGSUSED */
+hilclose(dev, flags)
+       dev_t dev;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register struct hilloopdev *dptr;
+       register int i;
+       u_char device = HILUNIT(dev);
+       char mask, lpctrl;
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilclose(%d): device %x\n", u.u_procp->p_pid, device);
+#endif
+
+       dptr = &hilp->hl_device[device];
+       if (device && (dptr->hd_flags & HIL_PSEUDO))
+               return (0);
+
+       if ((u.u_procp->p_flag & SHPUX) == 0) {
+               /*
+                * If this is the loop device,
+                * free up all queues belonging to this process.
+                */
+               if (device == 0) {
+                       for (i = 0; i < NHILQ; i++)
+                               if (hilp->hl_queue[i].hq_procp == u.u_procp)
+                                       (void) hilqfree(i);
+               } else {
+                       mask = ~hildevmask(device);
+                       (void) splhil();
+                       for (i = 0; i < NHILQ; i++)
+                               if (hilp->hl_queue[i].hq_procp == u.u_procp) {
+                                       dptr->hd_qmask &= ~hilqmask(i);
+                                       hilp->hl_queue[i].hq_devmask &= mask;
+                               }
+                       (void) spl0();
+               }
+       }
+       /*
+        * Always flush the read buffer
+        */
+       dptr->hd_flags &= ~(HIL_QUEUEIN|HIL_READIN|HIL_NOBLOCK);
+       ndflush(&dptr->hd_queue, dptr->hd_queue.c_cc);
+       /*
+        * Set keyboard back to cooked mode when closed.
+        */
+       (void) splhil();
+       if (device && device == hilp->hl_kbddev) {
+               mask = 1 << (hilp->hl_kbddev - 1);
+               send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &mask, 1, NULL);
+               hilp->hl_kbdflags &= ~(KBD_RAW|KBD_AR1|KBD_AR2);
+               /*
+                * XXX: We have had trouble with keyboards remaining raw
+                * after close due to the LPC_KBDCOOK bit getting cleared
+                * somewhere along the line.  Hence we check and reset
+                * LPCTRL if necessary.
+                */
+               send_hil_cmd(hilp->hl_addr, HIL_READLPCTRL, NULL, 0, &lpctrl);
+               if ((lpctrl & LPC_KBDCOOK) == 0) {
+                       printf("hilclose: bad LPCTRL %x, reset to %x\n",
+                              lpctrl, lpctrl|LPC_KBDCOOK);
+                       lpctrl |= LPC_KBDCOOK;
+                       send_hil_cmd(hilp->hl_addr, HIL_WRITELPCTRL,
+                                       &lpctrl, 1, NULL);
+               }
+#ifdef DEBUG
+               if (hildebug & HDB_KEYBOARD)
+                       printf("hilclose: keyboard %d cooked\n",
+                              hilp->hl_kbddev);
+#endif
+               kbdenable();
+       }
+       (void) spl0();
+       return (0);
+}
+
+/*
+ * Read interface to HIL device.
+ */
+hilread(dev, uio)
+       dev_t dev;
+       register struct uio *uio;
+{
+       struct hilloop *hilp = &hil0;           /* XXX */
+       register struct hilloopdev *dptr;
+       register int cc;
+       u_char device = HILUNIT(dev);
+       char buf[HILBUFSIZE];
+       int error;
+
+#if 0
+       /*
+        * XXX: Don't do this since HP-UX doesn't.
+        *
+        * Check device number.
+        * This check is necessary since loop can reconfigure.
+        */
+       if (device > hilp->hl_maxdev)
+               return(ENODEV);
+#endif
+
+       dptr = &hilp->hl_device[device];
+       if ((dptr->hd_flags & HIL_READIN) == 0)
+               return(ENODEV);
+
+       (void) splhil();
+       while (dptr->hd_queue.c_cc == 0) {
+               if (dptr->hd_flags & HIL_NOBLOCK) {
+                       spl0();
+                       return(EWOULDBLOCK);
+               }
+               dptr->hd_flags |= HIL_ASLEEP;
+               sleep((caddr_t)dptr, TTIPRI);
+       }
+       (void) spl0();
+
+       error = 0;
+       while (uio->uio_resid > 0 && error == 0) {
+               cc = hilq_to_b(&dptr->hd_queue, buf,
+                              MIN(uio->uio_resid, HILBUFSIZE));
+               if (cc <= 0)
+                       break;
+               error = uiomove(buf, cc, uio);
+       }
+       return(error);
+}
+
+hilioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       char device = HILUNIT(dev);
+       struct hilloopdev *dptr;
+       register int i;
+       u_char hold;
+       int error;
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilioctl(%d): dev %x cmd %x\n",
+                      u.u_procp->p_pid, device, cmd);
+#endif
+
+       dptr = &hilp->hl_device[device];
+       if ((dptr->hd_flags & HIL_ALIVE) == 0)
+               return (ENODEV);
+
+       /*
+        * Don't allow hardware ioctls on virtual devices.
+        * Note that though these are the BSD names, they have the same
+        * values as the HP-UX equivalents so we catch them as well.
+        */
+       if (dptr->hd_flags & HIL_PSEUDO) {
+               switch (cmd) {
+               case HILIOCSC:
+               case HILIOCID:
+               case HILIOCRN:
+               case HILIOCRS:
+               case HILIOCED:
+                       return(ENODEV);
+
+               /*
+                * XXX: should also return ENODEV but HP-UX compat
+                * breaks if we do.  They work ok right now because
+                * we only recognize one keyboard on the loop.  This
+                * will have to change if we remove that restriction.
+                */
+               case HILIOCAROFF:
+               case HILIOCAR1:
+               case HILIOCAR2:
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+#ifdef HPUXCOMPAT
+       if (u.u_procp->p_flag & SHPUX)
+               return(hpuxhilioctl(dev, cmd, data, flag));
+#endif
+
+       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+       bzero((caddr_t)hilp->hl_cmdbuf, HILBUFSIZE);
+       hilp->hl_cmddev = device;
+       error = 0;
+       switch (cmd) {
+
+       case HILIOCSBP:
+               /* Send four data bytes to the tone gererator. */
+               send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL);
+               /* Send the trigger beeper command to the 8042. */
+               send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
+               break;
+
+       case HILIOCRRT:
+               /* Transfer the real time to the 8042 data buffer */
+               send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
+               /* Read each byte of the real time */
+               for (i = 0; i < 5; i++) {
+                       send_hil_cmd(hilp->hl_addr, HIL_READTIME + i, NULL,
+                                       0, &hold);
+                       data[4-i] = hold;
+               }
+               break;
+               
+       case HILIOCRT:
+               for (i = 0; i < 4; i++) {
+                       send_hil_cmd(hilp->hl_addr, (cmd & 0xFF) + i,
+                                       NULL, 0, &hold);
+                       data[i] = hold;
+               }
+               break;
+
+       case HILIOCID:
+       case HILIOCSC:
+       case HILIOCRN:
+       case HILIOCRS:
+       case HILIOCED:
+               send_hildev_cmd(hilp, device, (cmd & 0xFF));
+               bcopy(hilp->hl_cmdbuf, data, hilp->hl_cmdbp-hilp->hl_cmdbuf);
+               break;
+
+        case HILIOCAROFF:
+        case HILIOCAR1:
+        case HILIOCAR2:
+               if (hilp->hl_kbddev) {
+                       hilp->hl_cmddev = hilp->hl_kbddev;
+                       send_hildev_cmd(hilp, hilp->hl_kbddev, (cmd & 0xFF));
+                       hilp->hl_kbdflags &= ~(KBD_AR1|KBD_AR2);
+                       if (cmd == HILIOCAR1)
+                               hilp->hl_kbdflags |= KBD_AR1;
+                       else if (cmd == HILIOCAR2)
+                               hilp->hl_kbdflags |= KBD_AR2;
+               }
+               break;
+
+       case HILIOCBEEP:
+               hilbeep(hilp, (struct _hilbell *)data);
+               break;
+
+       case FIONBIO:
+               dptr = &hilp->hl_device[device];
+               if (*(int *)data)
+                       dptr->hd_flags |= HIL_NOBLOCK;
+               else
+                       dptr->hd_flags &= ~HIL_NOBLOCK;
+               break;
+
+       /*
+        * FIOASYNC must be present for FIONBIO above to work!
+        * (See fcntl in kern_descrip.c).
+        */
+       case FIOASYNC:
+               break;
+
+        case HILIOCALLOCQ:
+               error = hilqalloc((struct hilqinfo *)data);
+               break;
+
+        case HILIOCFREEQ:
+               error = hilqfree(((struct hilqinfo *)data)->qid);
+               break;
+
+        case HILIOCMAPQ:
+               error = hilqmap(*(int *)data, device);
+               break;
+
+        case HILIOCUNMAPQ:
+               error = hilqunmap(*(int *)data, device);
+               break;
+
+       case HILIOCHPUX:
+               dptr = &hilp->hl_device[device];
+               dptr->hd_flags |= HIL_READIN;
+               dptr->hd_flags &= ~HIL_QUEUEIN;
+               break;
+
+        case HILIOCRESET:
+               hilreset(hilp);
+               break;
+               
+#ifdef DEBUG
+        case HILIOCTEST:
+               hildebug = *(int *) data;
+               break;
+#endif
+
+        default:
+               error = EINVAL;
+               break;
+
+       }
+       hilp->hl_cmddev = 0;
+       return(error);
+}
+
+#ifdef HPUXCOMPAT
+/* ARGSUSED */
+hpuxhilioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       char device = HILUNIT(dev);
+       struct hilloopdev *dptr;
+       register int i;
+       u_char hold;
+
+       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+       bzero((caddr_t)hilp->hl_cmdbuf, HILBUFSIZE);
+       hilp->hl_cmddev = device;
+       switch (cmd) {
+
+       case HILSC:
+       case HILID:
+       case HILRN:
+       case HILRS:
+       case HILED:
+       case HILP1:
+       case HILP2:
+       case HILP3:
+       case HILP4:
+       case HILP5:
+       case HILP6:
+       case HILP7:
+       case HILP:
+       case HILA1:
+       case HILA2:
+       case HILA3:
+       case HILA4:
+       case HILA5:
+       case HILA6:
+       case HILA7:
+       case HILA:
+               send_hildev_cmd(hilp, device, (cmd & 0xFF));
+               bcopy(hilp->hl_cmdbuf, data, hilp->hl_cmdbp-hilp->hl_cmdbuf);
+               break;
+
+        case HILDKR:
+        case HILER1:
+        case HILER2:
+               if (hilp->hl_kbddev) {
+                       hilp->hl_cmddev = hilp->hl_kbddev;
+                       send_hildev_cmd(hilp, hilp->hl_kbddev, (cmd & 0xFF));
+                       hilp->hl_kbdflags &= ~(KBD_AR1|KBD_AR2);
+                       if (cmd == HILIOCAR1)
+                               hilp->hl_kbdflags |= KBD_AR1;
+                       else if (cmd == HILIOCAR2)
+                               hilp->hl_kbdflags |= KBD_AR2;
+               }
+               break;
+
+       case EFTSBP:
+               /* Send four data bytes to the tone gererator. */
+               send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL);
+               /* Send the trigger beeper command to the 8042. */
+               send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
+               break;
+
+       case EFTRRT:
+               /* Transfer the real time to the 8042 data buffer */
+               send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
+               /* Read each byte of the real time */
+               for (i = 0; i < 5; i++) {
+                       send_hil_cmd(hilp->hl_addr, HIL_READTIME + i, NULL,
+                                       0, &hold);
+                       data[4-i] = hold;
+               }
+               break;
+               
+       case EFTRT:
+               for (i = 0; i < 4; i++) {
+                       send_hil_cmd(hilp->hl_addr, (cmd & 0xFF) + i,
+                                       NULL, 0, &hold);
+                       data[i] = hold;
+               }
+               break;
+
+        case EFTRLC:
+        case EFTRCC:
+               send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, &hold);
+               *data = hold;
+               break;
+               
+        case EFTSRPG:
+        case EFTSRD:
+        case EFTSRR:
+               send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), data, 1, NULL);
+               break;
+               
+       case EFTSBI:
+               hilbeep(hilp, (struct _hilbell *)data);
+               break;
+
+       case FIONBIO:
+               dptr = &hilp->hl_device[device];
+               if (*(int *)data)
+                       dptr->hd_flags |= HIL_NOBLOCK;
+               else
+                       dptr->hd_flags &= ~HIL_NOBLOCK;
+               break;
+
+       case FIOASYNC:
+               break;
+
+        default:
+               hilp->hl_cmddev = 0;
+               return(EINVAL);
+       }
+       hilp->hl_cmddev = 0;
+       return(0);
+}
+#endif
+
+/*
+ * XXX: the mmap inteface for HIL devices should be rethought.
+ * We used it only briefly in conjuntion with shared queues
+ * (instead of HILIOCMAPQ ioctl).  Perhaps mmap()ing a device
+ * should give a single queue per process.
+ */
+/* ARGSUSED */
+hilmap(dev, off, prot)
+       dev_t dev;
+       register int off;
+{
+#ifdef MMAP
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register struct hiliqueue *qp;
+       register int qnum;
+
+       /*
+        * Only allow mmap() on loop device
+        */
+       if (HILUNIT(dev) != 0 || off >= NHILQ*sizeof(HILQ))
+               return(-1);
+       /*
+        * Determine which queue we want based on the offset.
+        * Queue must belong to calling process.
+        */
+       qp = &hilp->hl_queue[off / sizeof(HILQ)];
+       if (qp->hq_procp != u.u_procp)
+               return(-1);
+
+       off %= sizeof(HILQ);
+       return(kvtop((u_int)qp->hq_eventqueue + off) >> PGSHIFT);
+#endif
+}
+
+/*ARGSUSED*/
+hilselect(dev, rw)
+       dev_t dev;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register struct hilloopdev *dptr;
+       register struct hiliqueue *qp;
+       register int mask;
+       int s, device;
+       
+       if (rw == FWRITE)
+               return (1);
+       device = HILUNIT(dev);
+
+       /*
+        * Read interface.
+        * Return 1 if there is something in the queue, 0 ow.
+        */
+       dptr = &hilp->hl_device[device];
+       if (dptr->hd_flags & HIL_READIN) {
+               s = splhil();
+               if (dptr->hd_queue.c_cc) {
+                       splx(s);
+                       return (1);
+               }
+               if (dptr->hd_selr &&
+                   dptr->hd_selr->p_wchan == (caddr_t)&selwait)
+                       dptr->hd_flags |= HIL_SELCOLL;
+               else
+                       dptr->hd_selr = u.u_procp;
+               splx(s);
+               return (0);
+       }
+
+       /*
+        * Make sure device is alive and real (or the loop device).
+        * Note that we do not do this for the read interface.
+        * This is primarily to be consistant with HP-UX.
+        */
+       if (device && (dptr->hd_flags & (HIL_ALIVE|HIL_PSEUDO)) != HIL_ALIVE)
+               return (1);
+
+       /*
+        * Select on loop device is special.
+        * Check to see if there are any data for any loop device
+        * provided it is associated with a queue belonging to this user.
+        */
+       if (device == 0)
+               mask = -1;
+       else
+               mask = hildevmask(device);
+       /*
+        * Must check everybody with interrupts blocked to prevent races.
+        */
+       s = splhil();
+       for (qp = hilp->hl_queue; qp < &hilp->hl_queue[NHILQ]; qp++)
+               if (qp->hq_procp == u.u_procp && (mask & qp->hq_devmask) &&
+                   qp->hq_eventqueue->hil_evqueue.head !=
+                   qp->hq_eventqueue->hil_evqueue.tail) {
+                       splx(s);
+                       return (1);
+               }
+
+       if (dptr->hd_selr && dptr->hd_selr->p_wchan == (caddr_t)&selwait)
+               dptr->hd_flags |= HIL_SELCOLL;
+       else
+               dptr->hd_selr = u.u_procp;
+       splx(s);
+       return (0);
+}
+
+hilint()
+{
+       struct hilloop *hilp = &hil0;           /* XXX */
+       register struct hil_dev *hildevice = hilp->hl_addr;
+       u_char c, stat;
+
+       stat = hildevice->hil_stat;
+       c = hildevice->hil_data;                /* clears interrupt */
+       hil_process_int(stat, c);
+}
+
+#include "ite.h"
+
+hil_process_int(stat, c)
+       register u_char stat, c;
+{
+       register struct hilloop *hilp;
+
+#ifdef DEBUG
+       if (hildebug & HDB_EVENTS)
+               printf("hilint: %x %x\n", stat, c);
+#endif
+
+       /* the shift enables the compiler to generate a jump table */
+       switch ((stat>>HIL_SSHIFT) & HIL_SMASK) {
+
+#if NITE > 0
+       case HIL_KEY:
+       case HIL_SHIFT:
+       case HIL_CTRL:
+       case HIL_CTRLSHIFT:
+               itefilter(stat, c);
+               return;
+#endif
+               
+       case HIL_STATUS:                        /* The status info. */
+               hilp = &hil0;                   /* XXX */
+               if (c & HIL_ERROR) {
+                       hilp->hl_cmddone = TRUE;
+                       if (c == HIL_RECONFIG)
+                               hilconfig(hilp);
+                       break;
+               }
+               if (c & HIL_COMMAND) {
+                       if (c & HIL_POLLDATA)   /* End of data */
+                               hilevent(hilp);
+                       else                    /* End of command */
+                               hilp->hl_cmdending = TRUE;
+                       hilp->hl_actdev = 0;
+               } else {
+                       if (c & HIL_POLLDATA) { /* Start of polled data */
+                               if (hilp->hl_actdev != 0)
+                                       hilevent(hilp);
+                               hilp->hl_actdev = (c & HIL_DEVMASK);
+                               hilp->hl_pollbp = hilp->hl_pollbuf;
+                       } else {                /* Start of command */
+                               if (hilp->hl_cmddev == (c & HIL_DEVMASK)) {
+                                       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+                                       hilp->hl_actdev = 0;
+                               }
+                       }
+               }
+               return;
+
+       case HIL_DATA:
+               hilp = &hil0;                   /* XXX */
+               if (hilp->hl_actdev != 0)       /* Collecting poll data */
+                       *hilp->hl_pollbp++ = c;
+               else if (hilp->hl_cmddev != 0)  /* Collecting cmd data */
+                       if (hilp->hl_cmdending) {
+                               hilp->hl_cmddone = TRUE;
+                               hilp->hl_cmdending = FALSE;
+                       } else  
+                               *hilp->hl_cmdbp++ = c;
+               return;
+               
+       case 0:         /* force full jump table */
+       default:
+               return;
+       }
+}
+
+#if defined(DEBUG) && !defined(PANICBUTTON)
+#define PANICBUTTON
+#endif
+
+/*
+ * Optimized macro to compute:
+ *     eq->head == (eq->tail + 1) % eq->size
+ * i.e. has tail caught up with head.  We do this because 32 bit long
+ * remaidering is expensive (a function call with our compiler).
+ */
+#define HQFULL(eq)     (((eq)->head?(eq)->head:(eq)->size) == (eq)->tail+1)
+#define HQVALID(eq) \
+       ((eq)->size == HEVQSIZE && (eq)->tail >= 0 && (eq)->tail < HEVQSIZE)
+
+hilevent(hilp)
+       struct hilloop *hilp;
+{
+       register struct hilloopdev *dptr = &hilp->hl_device[hilp->hl_actdev];
+       register int len, mask, qnum;
+       register u_char *cp, *pp;
+       register HILQ *hq;
+       struct timeval ourtime;
+       hil_packet *proto;
+       int s, len0;
+       long tenths;
+
+#ifdef PANICBUTTON
+       static int first;
+       extern int panicbutton;
+
+       cp = hilp->hl_pollbuf;
+       if (panicbutton && (*cp & HIL_KBDDATA)) {
+               if (*++cp == 0x4E)
+                       first = 1;
+               else if (first && *cp == 0x46 && !panicstr)
+                       panic("are we having fun yet?");
+               else
+                       first = 0;
+       }
+#endif
+#ifdef DEBUG
+       if (hildebug & HDB_EVENTS) {
+               printf("hilevent: dev %d pollbuf: ", hilp->hl_actdev);
+               printhilpollbuf(hilp);
+               printf("\n");
+       }
+#endif
+
+       /*
+        * Note that HIL_READIN effectively "shuts off" any queues
+        * that may have been in use at the time of an HILIOCHPUX call.
+        */
+       if (dptr->hd_flags & HIL_READIN) {
+               hpuxhilevent(hilp, dptr);
+               return;
+       }
+
+       /*
+        * If this device isn't on any queue or there are no data
+        * in the packet (can this happen?) do nothing.
+        */
+       if (dptr->hd_qmask == 0 ||
+           (len0 = hilp->hl_pollbp - hilp->hl_pollbuf) <= 0)
+               return;
+
+       /*
+        * Everybody gets the same time stamp
+        */
+       s = splclock();
+       ourtime = time;
+       splx(s);
+       tenths = (ourtime.tv_sec * 100) + (ourtime.tv_usec / 10000);
+
+       proto = NULL;
+       mask = dptr->hd_qmask;
+       for (qnum = 0; mask; qnum++) {
+               if ((mask & hilqmask(qnum)) == 0)
+                       continue;
+               mask &= ~hilqmask(qnum);
+               hq = hilp->hl_queue[qnum].hq_eventqueue;
+               
+               /*
+                * Ensure that queue fields that we rely on are valid
+                * and that there is space in the queue.  If either
+                * test fails, we just skip this queue.
+                */
+               if (!HQVALID(&hq->hil_evqueue) || HQFULL(&hq->hil_evqueue))
+                       continue;
+
+               /*
+                * Copy data to queue.
+                * If this is the first queue we construct the packet
+                * with length, timestamp and poll buffer data.
+                * For second and sucessive packets we just duplicate
+                * the first packet.
+                */
+               pp = (u_char *) &hq->hil_event[hq->hil_evqueue.tail];
+               if (proto == NULL) {
+                       proto = (hil_packet *)pp;
+                       cp = hilp->hl_pollbuf;
+                       len = len0;
+                       *pp++ = len + 6;
+                       *pp++ = hilp->hl_actdev;
+                       *(long *)pp = tenths;
+                       pp += sizeof(long);
+                       do *pp++ = *cp++; while (--len);
+               } else
+                       *(hil_packet *)pp = *proto;
+
+               if (++hq->hil_evqueue.tail == hq->hil_evqueue.size)
+                       hq->hil_evqueue.tail = 0;
+       }
+
+       /*
+        * Wake up anyone selecting on this device or the loop itself
+        */
+       if (dptr->hd_selr) {
+               selwakeup(dptr->hd_selr, dptr->hd_flags & HIL_SELCOLL);
+               dptr->hd_selr = NULL;
+               dptr->hd_flags &= ~HIL_SELCOLL;
+       }
+       dptr = &hilp->hl_device[HILLOOPDEV];
+       if (dptr->hd_selr) {
+               selwakeup(dptr->hd_selr, dptr->hd_flags & HIL_SELCOLL);
+               dptr->hd_selr = NULL;
+               dptr->hd_flags &= ~HIL_SELCOLL;
+       }
+}
+
+#undef HQFULL
+
+hpuxhilevent(hilp, dptr)
+       register struct hilloop *hilp;
+       register struct hilloopdev *dptr;
+{
+       register int len;
+       struct timeval ourtime;
+       long tstamp;
+       int s;
+
+       /*
+        * Everybody gets the same time stamp
+        */
+       s = splclock();
+       ourtime = time;
+       splx(s);
+       tstamp = (ourtime.tv_sec * 100) + (ourtime.tv_usec / 10000);
+
+       /*
+        * Each packet that goes into the buffer must be preceded by the
+        * number of bytes in the packet, and the timestamp of the packet.
+        * This adds 5 bytes to the packet size. Make sure there is enough
+        * room in the buffer for it, and if not, toss the packet.
+        */
+       len = hilp->hl_pollbp - hilp->hl_pollbuf;
+       if (dptr->hd_queue.c_cc <= (HILMAXCLIST - (len+5))) {
+               putc(len+5, &dptr->hd_queue);
+               (void) b_to_q((char *)&tstamp, sizeof tstamp, &dptr->hd_queue);
+               (void) b_to_q((char *)hilp->hl_pollbuf, len, &dptr->hd_queue);
+       }
+
+       /*
+        * Wake up any one blocked on a read or select
+        */
+       if (dptr->hd_flags & HIL_ASLEEP) {
+               dptr->hd_flags &= ~HIL_ASLEEP;
+               wakeup((caddr_t)dptr);
+       }
+       if (dptr->hd_selr) {
+               selwakeup(dptr->hd_selr, dptr->hd_flags & HIL_SELCOLL);
+               dptr->hd_selr = NULL;
+               dptr->hd_flags &= ~HIL_SELCOLL;
+       }
+}
+
+/*
+ * Shared queue manipulation routines
+ */
+
+hilqalloc(qip)
+       struct hilqinfo *qip;
+{
+#ifdef MAPMEM
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register HILQ *hq;
+       register int qnum;
+       struct mapmem *mp;
+       int hilqmapin();
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilqalloc(%d): addr %x\n",
+                      u.u_procp->p_pid, qip->addr);
+#endif
+       /*
+        * Find a free queue
+        */
+       for (qnum = 0; qnum < NHILQ; qnum++)
+               if (hilp->hl_queue[qnum].hq_procp == NULL)
+                       break;
+       if (qnum == NHILQ)
+               return(EMFILE);
+
+       /*
+        * Allocate and clear memory for the queue
+        */
+       if (hilp->hl_queue[qnum].hq_eventqueue)
+               panic("hilqalloc");
+       hq = (HILQ *) cialloc(sizeof(HILQ));
+       if (hq == NULL)
+               return(ENOMEM);
+       bzero((caddr_t)hq, sizeof(HILQ));
+       hilp->hl_queue[qnum].hq_eventqueue = hq;
+       hq->hil_evqueue.size = HEVQSIZE;
+
+       /*
+        * Map queue into user address space as instructed
+        */
+       mp = mmalloc(qnum, &qip->addr, sizeof(HILQ), MM_RW|MM_CI, &hilqops);
+       if (mp == MMNIL) {
+               cifree((caddr_t)hq, sizeof(HILQ));
+               hilp->hl_queue[qnum].hq_eventqueue = NULL;
+               return(u.u_error);
+       }
+       qip->qid = qnum;
+       if (!mmmapin(mp, hilqmapin)) {
+               mmfree(mp);
+               cifree((caddr_t)hq, sizeof(HILQ));
+               hilp->hl_queue[qnum].hq_eventqueue = NULL;
+               return(u.u_error);
+       }
+       hilp->hl_queue[qnum].hq_procp = u.u_procp;
+       hilp->hl_queue[qnum].hq_devmask = 0;
+       return(0);
+#else
+       return(EINVAL);
+#endif
+}
+
+hilqfree(qnum)
+       register int qnum;
+{
+#ifdef MAPMEM
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register struct mapmem *mp;
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilqfree(%d): qnum %d\n",
+                      u.u_procp->p_pid, qnum);
+#endif
+       if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != u.u_procp)
+               return(EINVAL);
+       for (mp = u.u_mmap; mp; mp = mp->mm_next)
+               if (qnum == mp->mm_id && mp->mm_ops == &hilqops) {
+                       hilqexit(mp);
+                       return(0);
+               }
+       panic("hilqfree");
+       /* NOTREACHED */
+#else
+       return(EINVAL);
+#endif
+}
+
+hilqmap(qnum, device)
+       register int qnum, device;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register struct hilloopdev *dptr = &hilp->hl_device[device];
+       int s;
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilqmap(%d): qnum %d device %x\n",
+                      u.u_procp->p_pid, qnum, device);
+#endif
+       if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != u.u_procp)
+               return(EINVAL);
+       if ((dptr->hd_flags & HIL_QUEUEIN) == 0)
+               return(EINVAL);
+       if (dptr->hd_qmask && u.u_uid && u.u_uid != dptr->hd_uid)
+               return(EPERM);
+
+       hilp->hl_queue[qnum].hq_devmask |= hildevmask(device);
+       if (dptr->hd_qmask == 0)
+               dptr->hd_uid = u.u_uid;
+       s = splhil();
+       dptr->hd_qmask |= hilqmask(qnum);
+       splx(s);
+#ifdef DEBUG
+       if (hildebug & HDB_MASK)
+               printf("hilqmap(%d): devmask %x qmask %x\n",
+                      u.u_procp->p_pid, hilp->hl_queue[qnum].hq_devmask,
+                      dptr->hd_qmask);
+#endif
+       return(0);
+}
+
+hilqunmap(qnum, device)
+       register int qnum, device;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       int s;
+
+#ifdef DEBUG
+       if (hildebug & HDB_FOLLOW)
+               printf("hilqunmap(%d): qnum %d device %x\n",
+                      u.u_procp->p_pid, qnum, device);
+#endif
+
+       if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != u.u_procp)
+               return(EINVAL);
+
+       hilp->hl_queue[qnum].hq_devmask &= ~hildevmask(device);
+       s = splhil();
+       hilp->hl_device[device].hd_qmask &= ~hilqmask(qnum);
+       splx(s);
+#ifdef DEBUG
+       if (hildebug & HDB_MASK)
+               printf("hilqunmap(%d): devmask %x qmask %x\n",
+                      u.u_procp->p_pid, hilp->hl_queue[qnum].hq_devmask,
+                      hilp->hl_device[device].hd_qmask);
+#endif
+       return(0);
+}
+
+#ifdef MAPMEM
+hilqmapin(mp, off)
+       struct mapmem *mp;
+{
+       struct hilloop *hilp = &hil0;           /* XXX */
+       register HILQ *hq = hilp->hl_queue[mp->mm_id].hq_eventqueue;
+
+       if (hq == NULL || off >= sizeof(HILQ))
+               return(-1);
+       return(kvtop((u_int)hq + off) >> PGSHIFT);
+}
+
+/*
+ * Fork hook.
+ * Unmap queue from child's address space
+ */
+hilqfork(mp, ischild)
+       struct mapmem *mp;
+{
+#ifdef DEBUG
+       if (hildebug & HDB_MMAP)
+               printf("hilqfork(%d): %s qnum %d\n", u.u_procp->p_pid,
+                      ischild ? "child" : "parent", mp->mm_id);
+#endif
+       if (ischild) {
+               mmmapout(mp);
+               mmfree(mp);
+       }
+}
+
+/*
+ * Vfork hook.
+ * Associate queue with child when VM resources are passed.
+ */
+hilqvfork(mp, fup, tup)
+       struct mapmem *mp;
+       struct user *fup, *tup;
+{
+       struct hilloop *hilp = &hil0;           /* XXX */
+       register struct hiliqueue *qp = &hilp->hl_queue[mp->mm_id];
+
+#ifdef DEBUG
+       if (hildebug & HDB_MMAP)
+               printf("hilqvfork(%d): from %x to %x qnum %d, qprocp %x\n",
+                      u.u_procp->p_pid, fup->u_procp, tup->u_procp,
+                      mp->mm_id, qp->hq_procp);
+#endif
+       if (qp->hq_procp == fup->u_procp)
+               qp->hq_procp = tup->u_procp;
+}
+
+/*
+ * Exit hook.
+ * Unmap all devices and free all queues.
+ */
+hilqexit(mp)
+       struct mapmem *mp;
+{
+       register struct hilloop *hilp = &hil0;  /* XXX */
+       register int mask, i;
+       int s;
+
+#ifdef DEBUG
+       if (hildebug & HDB_MMAP)
+               printf("hilqexit(%d): qnum %d\n", u.u_procp->p_pid, mp->mm_id);
+#endif
+       /*
+        * Atomically take all devices off the queue
+        */
+       mask = ~hilqmask(mp->mm_id);
+       s = splhil();
+       for (i = 0; i < NHILD; i++)
+               hilp->hl_device[i].hd_qmask &= mask;
+       splx(s);
+       /*
+        * Now unmap from user address space and free queue
+        */
+       i = mp->mm_id;
+       cifree((caddr_t)hilp->hl_queue[i].hq_eventqueue, sizeof(HILQ));
+       hilp->hl_queue[i].hq_eventqueue = NULL;
+       hilp->hl_queue[i].hq_procp = NULL;
+       mmfree(mp);
+}
+#endif
+
+#include "clist.h"
+
+/*
+ * This is just a copy of the virgin q_to_b routine with minor
+ * optimizations for HIL use.  It is used for two reasons:
+ * 1. If we have PAGE mode defined, the normal q_to_b processes
+ *    chars one at a time and breaks on newlines.
+ * 2. We don't have to raise the priority to spltty() for most
+ *    of the clist manipulations.
+ */
+hilq_to_b(q, cp, cc)
+       register struct clist *q;
+       register char *cp;
+{
+       register struct cblock *bp;
+       register int nc;
+       char *acp;
+       int s;
+       extern char cwaiting;
+
+       if (cc <= 0)
+               return (0);
+       s = splhil();
+       if (q->c_cc <= 0) {
+               q->c_cc = 0;
+               q->c_cf = q->c_cl = NULL;
+               splx(s);
+               return (0);
+       }
+       acp = cp;
+
+       while (cc) {
+               nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
+               nc = MIN(nc, cc);
+               nc = MIN(nc, q->c_cc);
+               (void) bcopy(q->c_cf, cp, (unsigned)nc);
+               q->c_cf += nc;
+               q->c_cc -= nc;
+               cc -= nc;
+               cp += nc;
+               if (q->c_cc <= 0) {
+                       bp = (struct cblock *)(q->c_cf - 1);
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       q->c_cf = q->c_cl = NULL;
+                       spltty();
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
+                       break;
+               }
+               if (((int)q->c_cf & CROUND) == 0) {
+                       bp = (struct cblock *)(q->c_cf);
+                       bp--;
+                       q->c_cf = bp->c_next->c_info;
+                       spltty();
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
+                       splhil();
+               }
+       }
+       splx(s);
+       return (cp-acp);
+}
+
+/*
+ * Cooked keyboard functions for ite driver.
+ * There is only one "cooked" ITE keyboard (the first keyboard found)
+ * per loop.  There may be other keyboards, but they will always be "raw".
+ */
+
+kbdbell()
+{
+       struct hilloop *hilp = &hil0;           /* XXX */
+
+       hilbeep(hilp, &default_bell);
+}
+
+kbdenable()
+{
+       struct hilloop *hilp = &hil0;   /* XXX */
+       register struct hil_dev *hildevice = hilp->hl_addr;
+       char db;
+
+       /* Set the autorepeat rate register */
+       db = ar_format(KBD_ARR);
+       send_hil_cmd(hildevice, HIL_SETARR, &db, 1, NULL);
+
+       /* Set the autorepeat delay register */
+       db = ar_format(KBD_ARD);
+       send_hil_cmd(hildevice, HIL_SETARD, &db, 1, NULL);
+
+       /* Enable interrupts */
+       send_hil_cmd(hildevice, HIL_INTON, NULL, 0, NULL);
+}
+
+kbddisable()
+{
+}
+
+/*
+ * XXX: read keyboard directly and return code.
+ * Used by console getchar routine.  Could really screw up anybody
+ * reading from the keyboard in the normal, interrupt driven fashion.
+ */
+kbdgetc(statp)
+       int *statp;
+{
+       struct hilloop *hilp = &hil0;           /* XXX */
+       register struct hil_dev *hildevice = hilp->hl_addr;
+       register int c, stat;
+       int s;
+
+       s = splhil();
+       while (((stat = hildevice->hil_stat) & HIL_DATA_RDY) == 0)
+               ;
+       c = hildevice->hil_data;
+       splx(s);
+       *statp = stat;
+       return(c);
+}
+
+/*
+ * Recoginize and clear keyboard generated NMIs.
+ * Returns 1 if it was ours, 0 otherwise.  Note that we cannot use
+ * send_hil_cmd() to issue the clear NMI command as that would actually
+ * lower the priority to splimp() and it doesn't wait for the completion
+ * of the command.  Either of these conditions could result in the
+ * interrupt reoccuring.  Note that we issue the CNMT command twice.
+ * This seems to be needed, once is not always enough!?!
+ */
+kbdnmi()
+{
+       register struct hilloop *hilp = &hil0;          /* XXX */
+
+       if ((*KBDNMISTAT & KBDNMI) == 0)
+               return(0);
+       HILWAIT(hilp->hl_addr);
+       hilp->hl_addr->hil_cmd = HIL_CNMT;
+       HILWAIT(hilp->hl_addr);
+       hilp->hl_addr->hil_cmd = HIL_CNMT;
+       HILWAIT(hilp->hl_addr);
+       return(1);
+}
+
+#define HILSECURITY    0x33
+#define HILIDENTIFY    0x03
+#define HILSCBIT       0x04
+
+/*
+ * Called at boot time to print out info about interesting devices
+ */
+hilinfo(hilp)
+       register struct hilloop *hilp;
+{
+       register int id, len;
+       register struct kbdmap *km;
+
+       /*
+        * Keyboard info.
+        */
+       if (hilp->hl_kbddev) {
+               printf("hil%d: ", hilp->hl_kbddev);
+               for (km = kbd_map; km->kbd_code; km++)
+                       if (km->kbd_code == hilp->hl_kbdlang) {
+                               printf("%s ", km->kbd_desc);
+                               break;
+                       }
+               printf("keyboard\n");
+       }
+       /*
+        * ID module.
+        * Attempt to locate the first ID module and print out its
+        * security code.  Is this a good idea??
+        */
+       id = hiliddev(hilp);
+       if (id) {
+               hilp->hl_cmdbp = hilp->hl_cmdbuf;
+               hilp->hl_cmddev = id;
+               send_hildev_cmd(hilp, id, HILSECURITY);
+               len = hilp->hl_cmdbp - hilp->hl_cmdbuf;
+               hilp->hl_cmdbp = hilp->hl_cmdbuf;
+               hilp->hl_cmddev = 0;
+               printf("hil%d: security code", id);
+               for (id = 0; id < len; id++)
+                       printf(" %x", hilp->hl_cmdbuf[id]);
+               while (id++ < 16)
+                       printf(" 0");
+               printf("\n");
+       }
+}
+
+#define HILAR1 0x3E
+#define HILAR2 0x3F
+
+/*
+ * Called after the loop has reconfigured.  Here we need to:
+ *     - determine how many devices are on the loop
+ *       (some may have been added or removed)
+ *     - locate the ITE keyboard (if any) and ensure
+ *       that it is in the proper state (raw or cooked)
+ *       and is set to use the proper language mapping table
+ *     - ensure all other keyboards are raw
+ * Note that our device state is now potentially invalid as
+ * devices may no longer be where they were.  What we should
+ * do here is either track where the devices went and move
+ * state around accordingly or, more simply, just mark all
+ * devices as HIL_DERROR and don't allow any further use until
+ * they are closed.  This is a little too brutal for my tastes,
+ * we prefer to just assume people won't move things around.
+ */
+hilconfig(hilp)
+       register struct hilloop *hilp;
+{
+       u_char db;
+       int s;
+
+       s = splhil();
+#ifdef DEBUG
+       if (hildebug & HDB_CONFIG) {
+               printf("hilconfig: reconfigured: ");
+               send_hil_cmd(hilp->hl_addr, HIL_READLPSTAT, NULL, 0, &db);
+               printf("LPSTAT %x, ", db);
+               send_hil_cmd(hilp->hl_addr, HIL_READLPCTRL, NULL, 0, &db);
+               printf("LPCTRL %x, ", db);
+               send_hil_cmd(hilp->hl_addr, HIL_READKBDSADR, NULL, 0, &db);
+               printf("KBDSADR %x\n", db);
+               hilreport(hilp);
+       }
+#endif
+       /*
+        * Determine how many devices are on the loop.
+        * Mark those as alive and real, all others as dead.
+        */
+       db = 0;
+       send_hil_cmd(hilp->hl_addr, HIL_READLPSTAT, NULL, 0, &db);
+       hilp->hl_maxdev = db & LPS_DEVMASK;
+       for (db = 1; db < NHILD; db++) {
+               if (db <= hilp->hl_maxdev)
+                       hilp->hl_device[db].hd_flags |= HIL_ALIVE;
+               else
+                       hilp->hl_device[db].hd_flags &= ~HIL_ALIVE;
+               hilp->hl_device[db].hd_flags &= ~HIL_PSEUDO;
+       }
+#ifdef DEBUG
+       if (hildebug & (HDB_CONFIG|HDB_KEYBOARD))
+               printf("hilconfig: max device %d\n", hilp->hl_maxdev);
+#endif
+       if (hilp->hl_maxdev == 0) {
+               hilp->hl_kbddev = 0;
+               splx(s);
+               return;
+       }
+       /*
+        * Find out where the keyboards are and record the ITE keyboard
+        * (first one found).  If no keyboards found, we are all done.
+        */
+       db = 0;
+       send_hil_cmd(hilp->hl_addr, HIL_READKBDSADR, NULL, 0, &db);
+#ifdef DEBUG
+       if (hildebug & HDB_KEYBOARD)
+               printf("hilconfig: keyboard: KBDSADR %x, old %d, new %d\n",
+                      db, hilp->hl_kbddev, ffs((int)db));
+#endif
+       hilp->hl_kbddev = ffs((int)db);
+       if (hilp->hl_kbddev == 0) {
+               splx(s);
+               return;
+       }
+       /*
+        * Determine if the keyboard should be cooked or raw and configure it.
+        */
+       db = (hilp->hl_kbdflags & KBD_RAW) ? 0 : 1 << (hilp->hl_kbddev - 1);
+       send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &db, 1, NULL);
+       /*
+        * Re-enable autorepeat in raw mode, cooked mode AR is not affected.
+        */
+       if (hilp->hl_kbdflags & (KBD_AR1|KBD_AR2)) {
+               db = (hilp->hl_kbdflags & KBD_AR1) ? HILAR1 : HILAR2;
+               hilp->hl_cmddev = hilp->hl_kbddev;
+               send_hildev_cmd(hilp, hilp->hl_kbddev, db);
+               hilp->hl_cmddev = 0;
+       }
+       /*
+        * Determine the keyboard language configuration, but don't
+        * override a user-specified setting.
+        */
+       db = 0;
+       send_hil_cmd(hilp->hl_addr, HIL_READKBDLANG, NULL, 0, &db);
+#ifdef DEBUG
+       if (hildebug & HDB_KEYBOARD)
+               printf("hilconfig: language: old %x new %x\n",
+                      hilp->hl_kbdlang, db);
+#endif
+       if (hilp->hl_kbdlang != KBD_SPECIAL) {
+               struct kbdmap *km;
+
+               for (km = kbd_map; km->kbd_code; km++)
+                       if (km->kbd_code == db) {
+                               hilp->hl_kbdlang = db;
+                               /* XXX */
+                               kbd_keymap = km->kbd_keymap;
+                               kbd_shiftmap = km->kbd_shiftmap;
+                               kbd_ctrlmap = km->kbd_ctrlmap;
+                               kbd_ctrlshiftmap = km->kbd_ctrlshiftmap;
+                               kbd_stringmap = km->kbd_stringmap;
+                       }
+       }
+       splx(s);
+}
+
+hilreset(hilp)
+       struct hilloop *hilp;
+{
+       register struct hil_dev *hildevice = hilp->hl_addr;
+       u_char db;
+
+       /*
+        * Initialize the loop: reconfigure, don't report errors,
+        * cook keyboards, and enable autopolling.
+        */
+       db = LPC_RECONF | LPC_KBDCOOK | LPC_NOERROR | LPC_AUTOPOLL;
+       send_hil_cmd(hildevice, HIL_WRITELPCTRL, &db, 1, NULL);
+       /*
+        * Delay one second for reconfiguration and then read the the
+        * data register to clear the interrupt (if the loop reconfigured).
+        */
+       DELAY(1000000);
+       if (hildevice->hil_stat & HIL_DATA_RDY)
+               db = hildevice->hil_data;
+       /*
+        * The HIL loop may have reconfigured.  If so we proceed on,
+        * if not we loop until a successful reconfiguration is reported
+        * back to us.  The HIL loop will continue to attempt forever.
+        * Probably not very smart.
+        */
+       do {
+               send_hil_cmd(hildevice, HIL_READLPSTAT, NULL, 0, &db);
+        } while ((db & (LPS_CONFFAIL|LPS_CONFGOOD)) == 0);
+       /*
+        * At this point, the loop should have reconfigured.
+        * The reconfiguration interrupt has already called hilconfig()
+        * so the keyboard has been determined.  All that is left is
+        * 
+        */
+#if 0
+       hilconfig(hilp);
+#endif
+       send_hil_cmd(hildevice, HIL_INTON, NULL, 0, NULL);
+}
+
+hilbeep(hilp, bp)
+       struct hilloop *hilp;
+       register struct _hilbell *bp;
+{
+       u_char buf[2];
+
+       buf[0] = ~((bp->duration - 10) / 10);
+       buf[1] = bp->frequency;
+       send_hil_cmd(hilp->hl_addr, HIL_SETTONE, buf, 2, NULL);
+}
+
+/*
+ * Locate and return the address of the first ID module, 0 if none present.
+ */
+hiliddev(hilp)
+       register struct hilloop *hilp;
+{
+       register int i, len;
+
+#ifdef DEBUG
+       if (hildebug & HDB_IDMODULE)
+               printf("hiliddev(%x): looking for idmodule...", hilp);
+#endif
+       for (i = 1; i <= hilp->hl_maxdev; i++) {
+               hilp->hl_cmdbp = hilp->hl_cmdbuf;
+               hilp->hl_cmddev = i;
+               send_hildev_cmd(hilp, i, HILIDENTIFY);
+               /*
+                * XXX: the final condition checks to ensure that the
+                * device ID byte is in the range of the ID module (0x30-0x3F)
+                */
+               len = hilp->hl_cmdbp - hilp->hl_cmdbuf;
+               if (len > 1 && (hilp->hl_cmdbuf[1] & HILSCBIT) &&
+                   (hilp->hl_cmdbuf[0] & 0xF0) == 0x30) {
+                       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+                       hilp->hl_cmddev = i;
+                       send_hildev_cmd(hilp, i, HILSECURITY);
+                       break;
+               }
+       }               
+       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+       hilp->hl_cmddev = 0;
+#ifdef DEBUG
+       if (hildebug & HDB_IDMODULE)
+               if (i <= hilp->hl_maxdev)
+                       printf("found at %d\n", i);
+               else
+                       printf("not found\n");
+#endif
+       return(i <= hilp->hl_maxdev ? i : 0);
+}
+
+/*
+ * Low level routines which actually talk to the 8042 chip.
+ */
+
+/*
+ * Send a command to the 8042 with zero or more bytes of data.
+ * If rdata is non-null, wait for and return a byte of data.
+ * We run at splimp() to make the transaction as atomic as
+ * possible without blocking the clock (is this necessary?)
+ */
+send_hil_cmd(hildevice, cmd, data, dlen, rdata)
+       register struct hil_dev *hildevice;
+       u_char cmd, *data, dlen;
+       u_char *rdata;
+{
+       u_char status;
+       int s = splimp();
+
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = cmd;
+       while (dlen--) {
+               HILWAIT(hildevice);
+               hildevice->hil_data = *data++;
+       }
+       if (rdata) {
+               do {
+                       HILDATAWAIT(hildevice);
+                       status = hildevice->hil_stat;
+                       *rdata = hildevice->hil_data;
+               } while (((status >> HIL_SSHIFT) & HIL_SMASK) != HIL_68K);
+       }
+       splx(s);
+}
+
+/*
+ * Send a command to a device on the loop.
+ * Since only one command can be active on the loop at any time,
+ * we must ensure that we are not interrupted during this process.
+ * Hence we mask interrupts to prevent potential access from most
+ * interrupt routines and turn off auto-polling to disable the
+ * internally generated poll commands.
+ *
+ * splhigh is extremely conservative but insures atomic operation,
+ * splimp (clock only interrupts) seems to be good enough in practice.
+ */
+send_hildev_cmd(hilp, device, cmd)
+       register struct hilloop *hilp;
+       char device, cmd;
+{
+       register struct hil_dev *hildevice = hilp->hl_addr;
+       u_char status, c;
+       int s = splimp();
+
+       polloff(hildevice);
+
+       /*
+        * Transfer the command and device info to the chip
+        */
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_STARTCMD;
+       HILWAIT(hildevice);
+       hildevice->hil_data = 8 + device;
+       HILWAIT(hildevice);
+       hildevice->hil_data = cmd;
+       HILWAIT(hildevice);
+       hildevice->hil_data = HIL_TIMEOUT;
+       /*
+        * Trigger the command and wait for completion
+        */
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_TRIGGER;
+       hilp->hl_cmddone = FALSE;
+       do {
+               HILDATAWAIT(hildevice);
+               status = hildevice->hil_stat;
+               c = hildevice->hil_data;
+               hil_process_int(status, c);
+       } while (!hilp->hl_cmddone);
+
+       pollon(hildevice);
+       splx(s);
+}
+
+/*
+ * Turn auto-polling off and on.
+ * Also disables and enable auto-repeat.  Why?
+ */
+polloff(hildevice)
+       register struct hil_dev *hildevice;
+{
+       register char db;
+
+       /*
+        * Turn off auto repeat
+        */
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_SETARR;
+       HILWAIT(hildevice);
+       hildevice->hil_data = 0;
+       /*
+        * Turn off auto-polling
+        */
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_READLPCTRL;
+       HILDATAWAIT(hildevice);
+       db = hildevice->hil_data;
+       db &= ~LPC_AUTOPOLL;
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_WRITELPCTRL;
+       HILWAIT(hildevice);
+       hildevice->hil_data = db;
+       /*
+        * Must wait til polling is really stopped
+        */
+       do {    
+               HILWAIT(hildevice);
+               hildevice->hil_cmd = HIL_READBUSY;
+               HILDATAWAIT(hildevice);
+               db = hildevice->hil_data;
+       } while (db & BSY_LOOPBUSY);
+}
+
+pollon(hildevice)
+       register struct hil_dev *hildevice;
+{
+       register char db;
+
+       /*
+        * Turn on auto polling
+        */
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_READLPCTRL;
+       HILDATAWAIT(hildevice);
+       db = hildevice->hil_data;
+       db |= LPC_AUTOPOLL;
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_WRITELPCTRL;
+       HILWAIT(hildevice);
+       hildevice->hil_data = db;
+       /*
+        * Turn on auto repeat
+        */
+       HILWAIT(hildevice);
+       hildevice->hil_cmd = HIL_SETARR;
+       HILWAIT(hildevice);
+       hildevice->hil_data = ar_format(KBD_ARR);
+}
+
+#ifdef DEBUG
+printhilpollbuf(hilp)
+       register struct hilloop *hilp;
+{
+       register u_char *cp;
+       register int i, len;
+
+       cp = hilp->hl_pollbuf;
+       len = hilp->hl_pollbp - cp;
+       for (i = 0; i < len; i++)
+               printf("%x ", hilp->hl_pollbuf[i]);
+       printf("\n");
+}
+
+printhilcmdbuf(hilp)
+       register struct hilloop *hilp;
+{
+       register u_char *cp;
+       register int i, len;
+
+       cp = hilp->hl_cmdbuf;
+       len = hilp->hl_cmdbp - cp;
+       for (i = 0; i < len; i++)
+               printf("%x ", hilp->hl_cmdbuf[i]);
+       printf("\n");
+}
+
+hilreport(hilp)
+       register struct hilloop *hilp;
+{
+       register int i, len;
+       int s = splhil();
+
+       for (i = 1; i <= hilp->hl_maxdev; i++) {
+               hilp->hl_cmdbp = hilp->hl_cmdbuf;
+               hilp->hl_cmddev = i;
+               send_hildev_cmd(hilp, i, HILIDENTIFY);
+               printf("hil%d: id: ", i);
+               printhilcmdbuf(hilp);
+               len = hilp->hl_cmdbp - hilp->hl_cmdbuf;
+               if (len > 1 && (hilp->hl_cmdbuf[1] & HILSCBIT)) {
+                       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+                       hilp->hl_cmddev = i;
+                       send_hildev_cmd(hilp, i, HILSECURITY);
+                       printf("hil%d: sc: ", i);
+                       printhilcmdbuf(hilp);
+               }
+       }               
+       hilp->hl_cmdbp = hilp->hl_cmdbuf;
+       hilp->hl_cmddev = 0;
+       splx(s);
+}
+#endif
diff --git a/usr/src/sys/hp/dev/hil_keymaps.c b/usr/src/sys/hp/dev/hil_keymaps.c
new file mode 100644 (file)
index 0000000..e58b634
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: hil_keymaps.c 1.1 89/08/22$
+ *
+ *     @(#)hil_keymaps.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ * Keymaps for various HP-HIL keyboard layouts.
+ * These tables apply only to keyboards in "cooked" mode.
+ * Currently only one is supported as an ITE keyboard.
+ *
+ * Maps are indexed by cooked keycode and contain the ASCII
+ * character for that keycode.  The map-set used depends on the
+ * keyboard "language".  The map used within that set depends on
+ * the shift/control status that is returned by the hardware along
+ * with the keycode.  If an entry is NULL for a key in the appropriate
+ * unshifted, shifted, control, or control-shifted table, then a
+ * single "string" table is consulted.  In this fashion, a multi-
+ * character sequence can be returned for a key press.  Note that
+ * control/shift status have no effect on multi-character lookup
+ * (i.e. there is only one string table per set, not four).
+ *
+ * Someday we could allow user-definable keymaps, but we would have
+ * to come up with a better format (at least externally).  This
+ * format takes up lots of space.  Having keymaps for all 18 or so
+ * HP supported layouts would be bad news.
+ */
+#include "param.h"
+#include "kbdmap.h"
+
+char   us_keymap[] = {
+       NULL,   '`',    '\\',   ESC,    NULL,   DEL,    NULL,   NULL,  
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,  
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,  
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   '\b',   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    'E',    '(',    ')',    '^',
+       '1',    '2',    '3',    '4',    '5',    '6',    '7',    '8',
+       '9',    '0',    '-',    '=',    '[',    ']',    ';',    '\'',
+       ',',    '.',    '/',    '\040', 'o',    'p',    'k',    'l',
+       'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
+       'a',    's',    'd',    'f',    'g',    'h',    'j',    'm',
+       'z',    'x',    'c',    'v',    'b',    'n',    NULL,   NULL
+};
+
+char   us_shiftmap[] = {
+       NULL,   '~',    '|',    DEL,    NULL,   DEL,    NULL,   NULL,
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   DEL,    NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    '`',    '|',    '\\',   '~',
+       '!',    '@',    '#',    '$',    '%',    '^',    '&',    '*',
+       '(',    ')',    '_',    '+',    '{',    '}',    ':',    '\"',
+       '<',    '>',    '?',    '\040', 'O',    'P',    'K',    'L',
+       'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
+       'A',    'S',    'D',    'F',    'G',    'H',    'J',    'M',
+       'Z',    'X',    'C',    'V',    'B',    'N',    NULL,   NULL
+};
+
+char   us_ctrlmap[] = {
+       NULL,   '`',    '\034', ESC,    NULL,   DEL,    NULL,   NULL,
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   '\b',   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    'E',    '(',    ')',    '\036',
+       '1',    '2',    '3',    '4',    '5',    '6',    '7',    '8',
+       '9',    '0',    '-',    '=',    '\033', '\035', ';',    '\'',
+       ',',    '.',    '/',    '\040', '\017', '\020', '\013', '\014',
+       '\021', '\027', '\005', '\022', '\024', '\031', '\025', '\011',
+       '\001', '\023', '\004', '\006', '\007', '\010', '\012', '\015',
+       '\032', '\030', '\003', '\026', '\002', '\016', NULL,   NULL
+};
+
+char   us_ctrlshiftmap[] = {
+       NULL,   '~',    '|',    DEL,    NULL,   DEL,    NULL,   NULL,
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   DEL,    NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    '`',    '|',    '\034', '~',
+       '!',    '\000', '#',    '$',    '%',    '\036', '&',    '*',
+       '(',    ')',    '\037', '+',    '{',    '}',    ':',    '\"',
+       '<',    '>',    '?',    '\040', '\017', '\020', '\013', '\014',
+       '\021', '\027', '\005', '\022', '\024', '\031', '\025', '\011',
+       '\001', '\023', '\004', '\006', '\007', '\010', '\012', '\015',
+       '\032', '\030', '\003', '\026', '\002', '\016', NULL,   NULL
+};
+
+char   *us_stringmap[] = {
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   "\033V","\033h",
+       "\033U",NULL,   NULL,   NULL,   NULL,   NULL,   "\033K","\033J",
+       NULL,   NULL,   NULL,   "\033p","\033q","\033t","\033u","\033v",
+       "\033r","\033s","\033B","\033A","\033w",NULL,   "\033D","\033C",
+       "\033L","\033M",NULL,   NULL,   "\033P",NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL
+};
+
+#ifdef UK_KEYBOARD
+char   uk_keymap[] = {
+       NULL,   '`',    '<',    ESC,    NULL,   DEL,    NULL,   NULL,  
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,  
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,  
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   '\b',   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    'E',    '(',    ')',    '^',
+       '1',    '2',    '3',    '4',    '5',    '6',    '7',    '8',
+       '9',    '0',    '+',    '\'',   '[',    ']',    '*',    '\\',
+       ',',    '.',    '-',    '\040', 'o',    'p',    'k',    'l',
+       'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
+       'a',    's',    'd',    'f',    'g',    'h',    'j',    'm',
+       'z',    'x',    'c',    'v',    'b',    'n',    NULL,   NULL
+};
+
+char   uk_shiftmap[] = {
+       NULL,   '~',    '>',    DEL,    NULL,   DEL,    NULL,   NULL,
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   DEL,    NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    '`',    '|',    '\\',   '~',
+       '!',    '\"',   '#',    '$',    '%',    '&',    '^',    '(',
+       ')',    '=',    '?',    '/',    '{',    '}',    '@',    '|',
+       ';',    ':',    '_',    '\040', 'O',    'P',    'K',    'L',
+       'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
+       'A',    'S',    'D',    'F',    'G',    'H',    'J',    'M',
+       'Z',    'X',    'C',    'V',    'B',    'N',    NULL,   NULL
+};
+
+char   uk_ctrlmap[] = {
+       NULL,   '`',    '<',    ESC,    NULL,   DEL,    NULL,   NULL,
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   '\b',   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    'E',    '(',    ')',    '\036',
+       '1',    '2',    '3',    '4',    '5',    '6',    '7',    '8',
+       '9',    '0',    '+',    '\'',   '\033', '\035', '*',    '\034',
+       ',',    '.',    '/',    '\040', '\017', '\020', '\013', '\014',
+       '\021', '\027', '\005', '\022', '\024', '\031', '\025', '\011',
+       '\001', '\023', '\004', '\006', '\007', '\010', '\012', '\015',
+       '\032', '\030', '\003', '\026', '\002', '\016', NULL,   NULL
+};
+
+char   uk_ctrlshiftmap[] = {
+       NULL,   '~',    '>',    DEL,    NULL,   DEL,    NULL,   NULL,
+       '\n',   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\n',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   '\t',   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   DEL,    NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       ESC,    '\r',   NULL,   '\n',   '0',    '.',    ',',    '+',
+       '1',    '2',    '3',    '-',    '4',    '5',    '6',    '*',
+       '7',    '8',    '9',    '/',    '`',    '|',    '\034', '~',
+       '!',    '\"',   '#',    '$',    '%',    '&',    '\036', '(',
+       ')',    '=',    '?',    '/',    '{',    '}',    '\000', '|',
+       ';',    ':',    '\037', '\040', '\017', '\020', '\013', '\014',
+       '\021', '\027', '\005', '\022', '\024', '\031', '\025', '\011',
+       '\001', '\023', '\004', '\006', '\007', '\010', '\012', '\015',
+       '\032', '\030', '\003', '\026', '\002', '\016', NULL,   NULL
+};
+#endif
+
+/*
+ * The keyboard map table.
+ * Lookup is by hardware returned language code.
+ */
+struct kbdmap kbd_map[] = {
+       KBD_US,         "US ASCII",
+       us_keymap,      us_shiftmap,    us_ctrlmap,     us_ctrlshiftmap,
+       us_stringmap,
+
+#ifdef UK_KEYBOARD
+       KBD_UK,         "United Kingdom",
+       uk_keymap,      uk_shiftmap,    uk_ctrlmap,     uk_ctrlshiftmap,
+       us_stringmap,
+#endif
+
+       0,              NULL,
+       NULL,           NULL,           NULL,           NULL,
+       NULL,
+};
diff --git a/usr/src/sys/hp/dev/hilioctl.h b/usr/src/sys/hp/dev/hilioctl.h
new file mode 100644 (file)
index 0000000..80d79ec
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: hilioctl.h 1.9 89/01/18$
+ *
+ *     @(#)hilioctl.h  7.1 (Berkeley) %G%
+ */
+
+struct _hilbell {
+       u_char  duration;
+       u_char  frequency;
+};
+
+struct _hilbuf16 {
+       u_char  string[16];
+};
+
+struct _hilbuf11 {
+       u_char  string[11];
+};
+
+struct _hilbuf5 {
+       u_char  string[5];
+};
+
+struct _hilbuf4 {
+       u_char  string[4];
+};
+
+struct _hilbuf2 {
+       u_char  string[2];
+};
+
+struct hilqinfo {
+       int     qid;
+       char    *addr;
+};
+
+/*
+ * HPUX ioctls (here for the benefit of the HIL driver).
+ * Named as they are under HPUX.
+ * The first set are loop device ioctls.
+ * The second set are ioctls for the 8042.
+ * Note that some are not defined as in HPUX
+ * due to the difference in the definitions of IOC_VOID.
+ */
+#define _IOHpux(x,y)   (IOC_IN|((x)<<8)|y)     /* IOC_IN is IOC_VOID */
+
+#define HILID  _IOR('h',0x03, struct _hilbuf11) /* Identify & describe */
+#define HILSC  _IOR('h',0x33, struct _hilbuf16) /* Security code */
+#define HILRN  _IOR('h',0x30, struct _hilbuf16) /* Report name */
+#define HILRS  _IOR('h',0x31, struct _hilbuf16) /* Report status */
+#define HILED  _IOR('h',0x32, struct _hilbuf16) /* Extended describe*/
+#define HILDKR  _IOHpux('h',0x3D)              /* Disable autorepeat */
+#define HILER1  _IOHpux('h',0x3E)              /* Autorepeat 1/30 */
+#define HILER2  _IOHpux('h',0x3F)              /* Autorepeat 1/60 */
+#define HILP1  _IOHpux('h',0x40)               /* Prompt 1 */
+#define HILP2  _IOHpux('h',0x41)               /* Prompt 2 */
+#define HILP3  _IOHpux('h',0x42)               /* Prompt 3 */
+#define HILP4  _IOHpux('h',0x43)               /* Prompt 4 */
+#define HILP5  _IOHpux('h',0x44)               /* Prompt 5 */
+#define HILP6  _IOHpux('h',0x45)               /* Prompt 6 */
+#define HILP7  _IOHpux('h',0x46)               /* Prompt 7 */
+#define HILP   _IOHpux('h',0x47)               /* Prompt */
+#define HILA1  _IOHpux('h',0x48)               /* Acknowledge 1 */
+#define HILA2  _IOHpux('h',0x49)               /* Acknowledge 2 */
+#define HILA3  _IOHpux('h',0x4A)               /* Acknowledge 3 */
+#define HILA4  _IOHpux('h',0x4B)               /* Acknowledge 4 */
+#define HILA5  _IOHpux('h',0x4C)               /* Acknowledge 5 */
+#define HILA6  _IOHpux('h',0x4D)               /* Acknowledge 6 */
+#define HILA7  _IOHpux('h',0x4E)               /* Acknowledge 7 */
+#define HILA   _IOHpux('h',0x4F)               /* Acknowledge */
+
+#define EFTSRD  _IOW('H',0xa0,char)            /* Set the repeat delay. */
+#define EFTSRR  _IOW('H',0xa2,char)            /* Set the repeat rate. */
+#define EFTSRPG _IOW('H',0xa6,char)            /* Set RPG interrupt rate. */
+#define EFTSBP  _IOW('H',0xc4,struct _hilbuf4) /* Send data to the beeper. */
+#define EFTRLC  _IOR('H',0x12,char)            /* Read the language code. */
+#define EFTRCC  _IOR('H',0x11,char)            /* Read configuration code. */
+#define EFTRRT  _IOR('H',0x31,struct _hilbuf5) /* Read the real time. */
+#define EFTRT   _IOR('H',0xf4,struct _hilbuf4) /* Read the timers for the
+                                                     four voices. */
+#define EFTSBI  _IOW('H',0xa3,struct _hilbuf2) /* Set the bell information. */
+
+/*
+ * BSD ioctls.
+ * Mostly the same as the HPUX versions except for shared-queue ioctls.
+ */
+#define HILIOCID       _IOR('h',0x03, struct _hilbuf11)
+#define HILIOCSC       _IOR('h',0x33, struct _hilbuf16)
+#define HILIOCRN       _IOR('h',0x30, struct _hilbuf16)
+#define HILIOCRS       _IOR('h',0x31, struct _hilbuf16)
+#define HILIOCED       _IOR('h',0x32, struct _hilbuf16)
+#define HILIOCAROFF    _IO('h',0x3D)
+#define HILIOCAR1      _IO('h',0x3E)
+#define HILIOCAR2      _IO('h',0x3F)
+#define HILIOCSBP      _IOW('H',0xc4,struct _hilbuf4)
+#define HILIOCRRT      _IOR('H',0x31,struct _hilbuf5)
+#define HILIOCRT       _IOR('H',0xf4,struct _hilbuf4)
+#define HILIOCBEEP     _IOW('H',0xA3,struct _hilbell)
+#      define  BELLDUR         80      /* tone duration in msec (10 - 2560) */
+#      define  BELLFREQ        8       /* tone frequency (0 - 63) */
+
+#define HILIOCALLOCQ   _IOWR('H',0x72, struct hilqinfo)        /* allocate queue */
+#define HILIOCFREEQ    _IOW('H',0x73, struct hilqinfo) /* deallocate queue */
+#define HILIOCMAPQ     _IOW('H',0x74, int)     /* map device to queue */
+#define HILIOCUNMAPQ   _IOW('H',0x75, int)     /* unmap device from dev */
+#define HILIOCTEST      _IOW('H',0x76, int)    /* Toggle debugging mode */
+#define HILIOCHPUX     _IO('H',0x77)           /* use HPUX (read) semantics */
+#define HILIOCRESET    _IO('H',0x78)           /* Reset the HIL loop. */
+
+/*
+ * HIL input queue.
+ * This is the circular queue (allocated by HILIOCALLOC) shared by kernel
+ * and user.  It consists of a sixteen byte header followed by space for
+ * 255 input data packets (a total of 4096 bytes).  The kernel adds packets
+ * at tail.  The user is expected to remove packets from head.  This is the
+ * only field in the header that the user should modify.
+ */
+typedef struct hil_packet {
+       u_char  size;           /* total packet size */
+       u_char  dev;            /* loop device packet was generated by */
+       long    tstamp;         /* time stamp */
+       u_char  data[10];       /* device data */
+} hil_packet;
+
+typedef struct hil_eventqueue {
+       int     size;
+       int     head;
+       int     tail;
+       int     pad;
+} hil_eventqueue;
+
+typedef union hilqueue {
+       char    hqu_size[0x1000];
+       struct  q_data {
+               hil_eventqueue  h_eventqueue;
+               hil_packet      h_event[1];
+       } q_data;
+#define hil_evqueue    q_data.h_eventqueue
+#define hil_event      q_data.h_event
+} HILQ;
+
+#define HEVQSIZE       \
+       ((sizeof(HILQ) - sizeof(struct q_data)) / sizeof(hil_packet) + 1)
diff --git a/usr/src/sys/hp/dev/hilreg.h b/usr/src/sys/hp/dev/hilreg.h
new file mode 100644 (file)
index 0000000..6dd1133
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: hilreg.h 1.8 89/08/24$
+ *
+ *     @(#)hilreg.h    7.1 (Berkeley) %G%
+ */
+
+struct hil_dev {
+       char    hil_pad0;
+       volatile char   hil_data;
+       char    hil_pad1;
+       volatile char   hil_cmd;
+#define hil_stat hil_cmd
+};
+
+#define        HILADDR                 ((struct hil_dev *)IOV(0x428000))
+#define BBCADDR                        ((struct hil_dev *)IOV(0x420000))  
+
+#define splhil                 spl1
+
+#define        HIL_BUSY                0x02
+#define HIL_DATA_RDY           0x01
+
+#define HILWAIT(hil_dev)       while ((hil_dev->hil_stat & HIL_BUSY))
+#define HILDATAWAIT(hil_dev)   while ((hil_dev->hil_stat & HIL_DATA_RDY) == 0)
+
+/* HIL status bits */
+#define        HIL_POLLDATA    0x10            /* HIL poll data follows */
+#define HIL_COMMAND    0x08            /* Start of original command */
+#define HIL_ERROR      0x080           /* HIL error */
+#define HIL_RECONFIG   0x080           /* HIL has reconfigured */
+#define        HIL_STATMASK    (HIL_DATA | HIL_COMMAND)
+
+#define HIL_SSHIFT             4       /* Bits to shift status over */
+#define HIL_SMASK              0xF     /* Service request status mask */
+#define HIL_DEVMASK            0x07
+
+/* HIL status types */
+#define        HIL_STATUS      0x5             /* HIL status in data register */
+#define        HIL_DATA        0x6             /* HIL data in data register */
+#define        HIL_CTRLSHIFT   0x8             /* key + CTRL + SHIFT */
+#define        HIL_CTRL        0x9             /* key + CTRL */
+#define        HIL_SHIFT       0xA             /* key + SHIFT */
+#define        HIL_KEY         0xB             /* key only */
+#define HIL_68K                0x4             /* Data from the 68k is ready */
+
+/* HIL commands */
+#define        HIL_SETARD      0xA0            /* set auto-repeat delay */
+#define        HIL_SETARR      0xA2            /* set auto-repeat rate */
+#define        HIL_SETTONE     0xA3            /* set tone generator */
+#define HIL_CNMT       0xB2            /* clear nmi */
+#define HIL_INTON      0x5C            /* Turn on interrupts. */
+#define HIL_INTOFF     0x5D            /* Turn off interrupts. */
+#define HIL_TRIGGER    0xC5            /* trigger command */
+#define HIL_STARTCMD   0xE0            /* start loop command */
+#define HIL_TIMEOUT    0xFE            /* timeout */
+#define HIL_READTIME   0x13            /* Read real time register */
+
+/* Read/write various registers on the 8042. */
+#define        HIL_READBUSY            0x02    /* internal "busy" register */
+#define HIL_READKBDLANG                0x12    /* read keyboard language code */
+#define        HIL_READKBDSADR         0xF9
+#define        HIL_WRITEKBDSADR        0xE9
+#define HIL_READLPSTAT         0xFA
+#define HIL_WRITELPSTAT        0xEA
+#define HIL_READLPCTRL         0xFB
+#define HIL_WRITELPCTRL        0xEB
+
+/* BUSY bits */
+#define BSY_LOOPBUSY   0x04
+
+/* LPCTRL bits */
+#define LPC_AUTOPOLL   0x01    /* enable auto-polling */
+#define LPC_NOERROR    0x02    /* don't report errors */
+#define LPC_NORECONF   0x04    /* don't report reconfigure */
+#define LPC_KBDCOOK    0x10    /* cook all keyboards */
+#define LPC_RECONF     0x80    /* reconfigure the loop */
+
+/* LPSTAT bits */
+#define LPS_DEVMASK    0x07    /* number of loop devices */
+#define LPS_CONFGOOD   0x08    /* reconfiguration worked */
+#define LPS_CONFFAIL   0x80    /* reconfiguration failed */
+
+/* HIL packet headers */
+#define HIL_MOUSEDATA   0x2
+#define HIL_KBDDATA     0x40
+  
+#define        HIL_MOUSEMOTION 0x02            /* mouse movement event */
+#define        HIL_KBDBUTTON   0x40            /* keyboard button event */
+#define HIL_MOUSEBUTTON 0x40            /* mouse button event */
+#define HIL_BUTTONBOX   0x60            /* button box event */
+#define HIL_TABLET      0x02            /* tablet motion event */
+#define HIL_KNOBBOX     0x03            /* knob box motion data */
+
+/* Magic */
+#define KBDNMISTAT             ((volatile char *)IOV(0x478005))
+#define        KBDNMI                  0x04
+
+/* For setting auto repeat on the keyboard */
+#define ar_format(x)   ~((x - 10) / 10)
+#define KBD_ARD                400             /* initial delay in msec (10 - 2560) */
+#define KBD_ARR                60              /* rate (10 - 2550 msec, 2551 == off)*/
diff --git a/usr/src/sys/hp/dev/hilvar.h b/usr/src/sys/hp/dev/hilvar.h
new file mode 100644 (file)
index 0000000..86f6012
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: hilvar.h 1.1 89/08/22$
+ *
+ *     @(#)hilvar.h    7.1 (Berkeley) %G%
+ */
+
+#ifndef TRUE
+#define TRUE   1
+#define FALSE  0
+#endif
+
+#define NHILD          8               /* 7 actual + loop pseudo (dev 0) */
+#define NHILQ          8               /* must be <= sizeof(int) */
+
+#define HILBUFSIZE     40              /* size of interrupt poll buffer */
+#define HILMAXCLIST    1024            /* max chars in clists for HPUX io */
+
+#define HILLOOPDEV     0               /* loop device index */
+
+/*
+ * XXX: HPUX minor numbers are of the form "D0" where D is the device number
+ * BSD uses "0D".  For compatibility we accept either.  Maybe we should just
+ * use the HPUX numbering.
+ */
+#define HILUNIT(d)     (((((d)>>4)&7)==0)?((d)&7):(((d)>>4)&7))
+
+#define        hildevmask(d)   (1 << (d))
+#define        hilqmask(q)     (1 << (q))
+
+struct hiliqueue {
+       HILQ    *hq_eventqueue;         /* input queue shared with user */
+       struct  proc *hq_procp;         /* process this queue belongs to */
+       char    hq_devmask;             /* devices mapped to this queue */
+};
+
+struct hilloopdev {
+       int     hd_flags;               /* device state */
+       int     hd_qmask;               /* queues this device is mapped to */
+       struct  clist hd_queue;         /* event queue for HPUX-style input */
+       struct  proc *hd_selr;          /* process read selecting */
+       uid_t   hd_uid;                 /* uid of mapping process */
+};
+
+/* hd_flags */
+#define        HIL_ALIVE       0x01    /* device is present */
+#define HIL_PSEUDO     0x02    /* device is virtual */
+#define HIL_READIN     0x04    /* device using read() input interface */
+#define HIL_QUEUEIN    0x08    /* device using shared Q input interface */
+#define HIL_SELCOLL    0x10    /* select collision on device */
+#define HIL_NOBLOCK    0x20    /* device is in non-blocking read mode */
+#define HIL_ASLEEP     0x40    /* process awaiting input on device */
+#define HIL_DERROR     0x80    /* loop has reconfigured, reality altered */
+
+struct hilloop {
+       struct  hil_dev *hl_addr;       /* base of hardware registers */
+       u_char  hl_cmddone;             /* */
+       u_char  hl_cmdending;           /* */
+       u_char  hl_actdev;              /* current input device */
+       u_char  hl_cmddev;              /* device to perform command on */
+       u_char  hl_pollbuf[HILBUFSIZE]; /* interrupt time input buffer */
+       u_char  hl_cmdbuf[HILBUFSIZE];  /* */
+       u_char  *hl_pollbp;             /* pointer into hl_pollbuf */
+       u_char  *hl_cmdbp;              /* pointer into hl_cmdbuf */
+       struct  hiliqueue hl_queue[NHILQ];      /* input queues */
+       struct  hilloopdev hl_device[NHILD];    /* device data */
+       u_char  hl_maxdev;              /* number of devices on loop */
+       u_char  hl_kbddev;              /* keyboard device on loop */
+       u_char  hl_kbdlang;             /* keyboard language */
+       u_char  hl_kbdflags;            /* keyboard state */
+};
+
+/* hl_kbdflags */
+#define KBD_RAW                0x01            /* keyboard is raw */
+#define KBD_AR1                0x02            /* keyboard auto-repeat rate 1 */
+#define KBD_AR2                0x04            /* keyboard auto-repeat rate 2 */
diff --git a/usr/src/sys/hp/dev/ite.c b/usr/src/sys/hp/dev/ite.c
new file mode 100644 (file)
index 0000000..b410fdd
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: ite.c 1.22 89/08/17$
+ *
+ *     @(#)ite.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ * Bit-mapped display terminal emulator machine independent code.
+ * This is a very rudimentary.  Much more can be abstracted out of
+ * the hardware dependent routines.
+ */
+#include "ite.h"
+#if NITE > 0
+
+#include "grf.h"
+
+#undef NITE
+#define NITE   NGRF
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+#include "malloc.h"
+
+#include "itevar.h"
+#include "iteioctl.h"
+#include "kbdmap.h"
+
+#include "machine/cpu.h"
+
+#define set_attr(ip, attr)     ((ip)->attribute |= (attr))
+#define clr_attr(ip, attr)     ((ip)->attribute &= ~(attr))
+
+extern  int nodev();
+
+int topcat_scroll(),   topcat_init(),          topcat_deinit();
+int topcat_clear(),    topcat_putc(),          topcat_cursor();
+int gatorbox_scroll(), gatorbox_init(),        gatorbox_deinit();
+int gatorbox_clear(),  gatorbox_putc(),        gatorbox_cursor();
+int rbox_scroll(),     rbox_init(),            rbox_deinit();
+int rbox_clear(),      rbox_putc(),            rbox_cursor();
+int dvbox_scroll(),    dvbox_init(),           dvbox_deinit();
+int dvbox_clear(),     dvbox_putc(),           dvbox_cursor();
+
+struct itesw itesw[] =
+{
+       topcat_init,            topcat_deinit,          topcat_clear,
+       topcat_putc,            topcat_cursor,          topcat_scroll,
+
+       gatorbox_init,          gatorbox_deinit,        gatorbox_clear,
+       gatorbox_putc,          gatorbox_cursor,        gatorbox_scroll,
+
+       rbox_init,              rbox_deinit,            rbox_clear,
+       rbox_putc,              rbox_cursor,            rbox_scroll,
+
+       dvbox_init,             dvbox_deinit,           dvbox_clear,
+       dvbox_putc,             dvbox_cursor,           dvbox_scroll,
+};
+
+/*
+ * # of chars are output in a single itestart() call.
+ * If this is too big, user processes will be blocked out for
+ * long periods of time while we are emptying the queue in itestart().
+ * If it is too small, console output will be very ragged.
+ */
+int    iteburst = 64;
+
+int    nite = NITE;
+struct  tty *kbd_tty = NULL;
+struct tty ite_tty[NITE];
+struct  ite_softc ite_softc[NITE];
+
+int    itestart();
+extern int ttrstrt();
+extern struct tty *constty;
+
+/*
+ * Primary attribute buffer to be used by the first bitmapped console
+ * found. Secondary displays alloc the attribute buffer as needed.
+ * Size is based on a 68x128 display, which is currently our largest.
+ */
+u_char  console_attributes[0x2200];
+
+/*
+ * Perform functions necessary to setup device as a terminal emulator.
+ */
+iteon(dev, flag)
+       dev_t dev;
+{
+       int unit = UNIT(dev);
+       struct tty *tp = &ite_tty[unit];
+       struct ite_softc *ip = &ite_softc[unit];
+
+       if (unit < 0 || unit >= NITE || (ip->flags&ITE_ALIVE) == 0)
+               return(ENXIO);
+       /* force ite active, overriding graphics mode */
+       if (flag & 1) {
+               ip->flags |= ITE_ACTIVE;
+               ip->flags &= ~(ITE_INGRF|ITE_INITED);
+       }
+       /* leave graphics mode */
+       if (flag & 2) {
+               ip->flags &= ~ITE_INGRF;
+               if ((ip->flags & ITE_ACTIVE) == 0)
+                       return(0);
+       }
+       ip->flags |= ITE_ACTIVE;
+       if (ip->flags & ITE_INGRF)
+               return(0);
+       if (kbd_tty == NULL || kbd_tty == tp) {
+               kbd_tty = tp;
+               kbdenable();
+       }
+       iteinit(dev);
+       return(0);
+}
+
+iteinit(dev)
+     dev_t dev;
+{
+       int unit = UNIT(dev);
+       struct ite_softc *ip = &ite_softc[unit];
+
+       if (ip->flags & ITE_INITED)
+               return;
+       
+       ip->curx = 0;
+       ip->cury = 0;
+       ip->cursorx = 0;
+       ip->cursory = 0;
+
+       (*itesw[ip->type].ite_init)(ip);
+       (*itesw[ip->type].ite_cursor)(ip, DRAW_CURSOR);
+
+       ip->attribute = 0;
+       if (ip->attrbuf == NULL)
+               ip->attrbuf = (u_char *)
+                       malloc(ip->rows * ip->cols, M_DEVBUF, M_WAITOK);
+       bzero(ip->attrbuf, (ip->rows * ip->cols));
+
+       ip->imode = 0;
+       ip->flags |= ITE_INITED;
+}
+
+/*
+ * "Shut down" device as terminal emulator.
+ * Note that we do not deinit the console device unless forced.
+ * Deinit'ing the console every time leads to a very active
+ * screen when processing /etc/rc.
+ */
+iteoff(dev, flag)
+       dev_t dev;
+{
+       register struct ite_softc *ip = &ite_softc[UNIT(dev)];
+
+       if (flag & 2)
+               ip->flags |= ITE_INGRF;
+       if ((ip->flags & ITE_ACTIVE) == 0)
+               return;
+       if ((flag & 1) ||
+           (ip->flags & (ITE_INGRF|ITE_ISCONS|ITE_INITED)) == ITE_INITED)
+               (*itesw[ip->type].ite_deinit)(ip);
+       if ((flag & 2) == 0)
+               ip->flags &= ~ITE_ACTIVE;
+}
+
+/*ARGSUSED*/
+iteopen(dev, flag)
+       dev_t dev;
+{
+       int unit = UNIT(dev);
+       register struct tty *tp = &ite_tty[unit];
+       register struct ite_softc *ip = &ite_softc[unit];
+       register int error;
+       int first = 0;
+
+       if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+               return (EBUSY);
+       if ((ip->flags & ITE_ACTIVE) == 0) {
+               error = iteon(dev, 0);
+               if (error)
+                       return (error);
+               first = 1;
+       }
+       tp->t_oproc = itestart;
+       tp->t_param = NULL;
+       tp->t_dev = dev;
+       if ((tp->t_state&TS_ISOPEN) == 0) {
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = CS8|CREAD;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+               tp->t_state = TS_ISOPEN|TS_CARR_ON;
+               ttsetwater(tp);
+       }
+       error = (*linesw[tp->t_line].l_open)(dev, tp);
+       if (error == 0) {
+               tp->t_winsize.ws_row = ip->rows;
+               tp->t_winsize.ws_col = ip->cols;
+       } else if (first)
+               iteoff(dev, 0);
+       return (error);
+}
+
+/*ARGSUSED*/
+iteclose(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp = &ite_tty[UNIT(dev)];
+
+       (*linesw[tp->t_line].l_close)(tp);
+       ttyclose(tp);
+       iteoff(dev, 0);
+       return(0);
+}
+
+iteread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp = &ite_tty[UNIT(dev)];
+
+       return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+itewrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       int unit = UNIT(dev);
+       register struct tty *tp = &ite_tty[unit];
+
+       if ((ite_softc[unit].flags & ITE_ISCONS) && constty &&
+           (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN))
+               tp = constty;
+       return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+iteioctl(dev, cmd, addr, flag)
+       dev_t dev;
+       caddr_t addr;
+{
+       register struct tty *tp = &ite_tty[UNIT(dev)];
+       int error;
+
+       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr, flag);
+       if (error >= 0)
+               return (error);
+       error = ttioctl(tp, cmd, addr, flag);
+       if (error >= 0)
+               return (error);
+       return (ENOTTY);
+}
+
+itestart(tp)
+       register struct tty *tp;
+{
+       register int cc, s;
+       int hiwat = 0;
+
+       s = spltty();
+       if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) {
+               splx(s);
+               return;
+       }
+       tp->t_state |= TS_BUSY;
+       cc = tp->t_outq.c_cc;
+       if (cc <= tp->t_lowat) {
+               if (tp->t_state & TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup(&tp->t_outq);
+               }
+               if (tp->t_wsel) {
+                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+                       tp->t_wsel = 0;
+                       tp->t_state &= ~TS_WCOLL;
+               }
+       }
+       /*
+        * Limit the amount of output we do in one burst
+        * to prevent hogging the CPU.
+        */
+       if (cc > iteburst) {
+               hiwat++;
+               cc = iteburst;
+       }
+       while (--cc >= 0) {
+               register int c;
+
+               c = getc(&tp->t_outq);
+               /*
+                * iteputchar() may take a long time and we don't want to
+                * block all interrupts for long periods of time.  Since
+                * there is no need to stay at high priority while outputing
+                * the character (since we don't have to worry about
+                * interrupts), we don't.  We just need to make sure that
+                * we don't reenter iteputchar, which is guarenteed by the
+                * earlier setting of TS_BUSY.
+                */
+               splx(s);
+               iteputchar(c, tp->t_dev);
+               spltty();
+       }
+       if (hiwat) {
+               tp->t_state |= TS_TIMEOUT;
+               timeout(ttrstrt, tp, 1);
+       }
+       tp->t_state &= ~TS_BUSY;
+       splx(s);
+}
+
+itefilter(stat, c)
+     register char stat, c;
+{
+       static int capsmode = 0;
+       static int metamode = 0;
+       register char code, *str;
+
+       if (kbd_tty == NULL)
+               return;
+
+       switch (c & 0xFF) {
+       case KBD_CAPSLOCK:
+               capsmode = !capsmode;
+               return;
+
+       case KBD_EXT_LEFT_DOWN:
+       case KBD_EXT_RIGHT_DOWN:
+               metamode = 1;
+               return;
+               
+       case KBD_EXT_LEFT_UP:
+       case KBD_EXT_RIGHT_UP:
+               metamode = 0;
+               return;
+       }
+
+       c &= KBD_CHARMASK;
+       switch ((stat>>KBD_SSHIFT) & KBD_SMASK) {
+
+       case KBD_KEY:
+               if (!capsmode) {
+                       code = kbd_keymap[c];
+                       break;
+               }
+               /* fall into... */
+
+       case KBD_SHIFT:
+               code = kbd_shiftmap[c];
+               break;
+
+       case KBD_CTRL:
+               code = kbd_ctrlmap[c];
+               break;
+               
+       case KBD_CTRLSHIFT:     
+               code = kbd_ctrlshiftmap[c];
+               break;
+        }
+
+       if (code == NULL && (str = kbd_stringmap[c]) != NULL) {
+               while (*str)
+                       (*linesw[kbd_tty->t_line].l_rint)(*str++, kbd_tty);
+       } else {
+               if (metamode)
+                       code |= 0x80;
+               (*linesw[kbd_tty->t_line].l_rint)(code, kbd_tty);
+       }
+}
+
+iteputchar(c, dev)
+       register int c;
+       dev_t dev;  
+{
+       int unit = UNIT(dev);
+       register struct ite_softc *ip = &ite_softc[unit];
+       register struct itesw *sp = &itesw[ip->type];
+       register int n;
+
+       if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE)
+               return;
+
+       if (ip->escape) {
+doesc:
+               switch (ip->escape) {
+
+               case '&':                       /* Next can be a,d, or s */
+                       if (ip->fpd++) {
+                               ip->escape = c;
+                               ip->fpd = 0;
+                       }
+                       return;
+
+               case 'a':                               /* cursor change */
+                       switch (c) {
+
+                       case 'Y':                       /* Only y coord. */
+                               ip->cury = MIN(ip->pos, ip->rows-1);
+                               ip->pos = 0;
+                               ip->escape = 0;
+                               (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                               clr_attr(ip, ATTR_INV);
+                               break;
+
+                       case 'y':                       /* y coord first */
+                               ip->cury = MIN(ip->pos, ip->rows-1);
+                               ip->pos = 0;
+                               ip->fpd = 0;
+                               break;
+
+                       case 'C':                       /* x coord */
+                               ip->curx = MIN(ip->pos, ip->cols-1);
+                               ip->pos = 0;
+                               ip->escape = 0;
+                               (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                               clr_attr(ip, ATTR_INV);
+                               break;
+
+                       default:             /* Possibly a 3 digit number. */
+                               if (c >= '0' && c <= '9' && ip->fpd < 3) {
+                                       ip->pos = ip->pos * 10 + (c - '0');
+                                       ip->fpd++;
+                               } else {
+                                       ip->pos = 0;
+                                       ip->escape = 0;
+                               }
+                               break;
+                       }
+                       return;
+
+               case 'd':                               /* attribute change */
+                       switch (c) {
+
+                       case 'B':
+                               set_attr(ip, ATTR_INV);
+                               break;
+                       case 'D':
+                               /* XXX: we don't do anything for underline */
+                               set_attr(ip, ATTR_UL);
+                               break;
+                       case '@':
+                               clr_attr(ip, ATTR_ALL);
+                               break;
+                       }
+                       ip->escape = 0;
+                       return;
+
+               case 's':                               /* keypad control */
+                       switch (ip->fpd) {
+
+                       case 0:
+                               ip->hold = c;
+                               ip->fpd++;
+                               return;
+
+                       case 1:
+                               if (c == 'A') {
+                                       switch (ip->hold) {
+       
+                                       case '0':
+                                               clr_attr(ip, ATTR_KPAD);
+                                               break;
+                                       case '1':
+                                               set_attr(ip, ATTR_KPAD);
+                                               break;
+                                       }
+                               }
+                               ip->hold = 0;
+                       }
+                       ip->escape = 0;
+                       return;
+
+               case 'i':                       /* back tab */
+                       if (ip->curx > TABSIZE) {
+                               n = ip->curx - (ip->curx & (TABSIZE - 1));
+                               ip->curx -= n;
+                       } else
+                               ip->curx = 0;
+                       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                       ip->escape = 0;
+                       return;
+
+               case '3':                       /* clear all tabs */
+                       goto ignore;
+
+               case 'K':                       /* clear_eol */
+                       ite_clrtoeol(ip, sp, ip->cury, ip->curx);
+                       ip->escape = 0;
+                       return;
+
+               case 'J':                       /* clear_eos */
+                       ite_clrtoeos(ip, sp);
+                       ip->escape = 0;
+                       return;
+
+               case 'B':                       /* cursor down 1 line */
+                       if (++ip->cury == ip->rows) {
+                               --ip->cury;
+                               (*sp->ite_scroll)(ip, 1, 0, 1, SCROLL_UP);
+                               ite_clrtoeol(ip, sp, ip->cury, 0);
+                       }
+                       else
+                               (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                       clr_attr(ip, ATTR_INV);
+                       ip->escape = 0;
+                       return;
+
+               case 'C':                       /* cursor forward 1 char */
+                       ip->escape = 0;
+                       itecheckwrap(ip, sp);
+                       return;
+
+               case 'A':                       /* cursor up 1 line */
+                       if (ip->cury > 0) {
+                               ip->cury--;
+                               (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                       }
+                       ip->escape = 0;
+                       clr_attr(ip, ATTR_INV);
+                       return;
+
+               case 'P':                       /* delete character */
+                       ite_dchar(ip, sp);
+                       ip->escape = 0;
+                       return;
+
+               case 'M':                       /* delete line */
+                       ite_dline(ip, sp);
+                       ip->escape = 0;
+                       return;
+
+               case 'Q':                       /* enter insert mode */
+                       ip->imode = 1;
+                       ip->escape = 0;
+                       return;
+
+               case 'R':                       /* exit insert mode */
+                       ip->imode = 0;
+                       ip->escape = 0;
+                       return;
+
+               case 'L':                       /* insert blank line */
+                       ite_iline(ip, sp);
+                       ip->escape = 0;
+                       return;
+
+               case 'h':                       /* home key */
+                       ip->cury = ip->curx = 0;
+                       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                       ip->escape = 0;
+                       return;
+
+               case 'D':                       /* left arrow key */
+                       if (ip->curx > 0) {
+                               ip->curx--;
+                               (*sp->ite_cursor)(ip, MOVE_CURSOR);
+                       }
+                       ip->escape = 0;
+                       return;
+
+               case '1':                       /* set tab in all rows */
+                       goto ignore;
+
+               case ESC:
+                       if ((ip->escape = c) == ESC)
+                               break;
+                       ip->fpd = 0;
+                       goto doesc;
+
+               default:
+ignore:
+                       ip->escape = 0;
+                       return;
+
+               }
+       }
+
+       switch (c &= 0x7F) {
+
+       case '\n':
+
+               if (++ip->cury == ip->rows) {
+                       --ip->cury;
+                       (*sp->ite_scroll)(ip, 1, 0, 1, SCROLL_UP);
+                       ite_clrtoeol(ip, sp, ip->cury, 0);
+               }
+               else
+                       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+               clr_attr(ip, ATTR_INV);
+               break;
+
+       case '\r':
+               if (ip->curx) {
+                       ip->curx = 0;
+                       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+               }
+               break;
+       
+       case '\b':
+               if (--ip->curx < 0)
+                       ip->curx = 0;
+               else
+                       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+               break;
+
+       case '\t':
+               if (ip->curx < TABEND(unit)) {
+                       n = TABSIZE - (ip->curx & (TABSIZE - 1));
+                       ip->curx += n;
+                       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+               } else
+                       itecheckwrap(ip, sp);
+               break;
+
+       case CTRL('G'):
+               if (&ite_tty[unit] == kbd_tty)
+                       kbdbell();
+               break;
+
+       case ESC:
+               ip->escape = ESC;
+               break;
+
+       default:
+               if (c < ' ' || c == DEL)
+                       break;
+               if (ip->imode)
+                       ite_ichar(ip, sp);
+               if ((ip->attribute & ATTR_INV) || attrtest(ip, ATTR_INV)) {
+                       attrset(ip, ATTR_INV);
+                       (*sp->ite_putc)(ip, c, ip->cury, ip->curx, ATTR_INV);
+               }                       
+               else
+                       (*sp->ite_putc)(ip, c, ip->cury, ip->curx, ATTR_NOR);
+               (*sp->ite_cursor)(ip, DRAW_CURSOR);
+               itecheckwrap(ip, sp);
+               break;
+       }
+}
+
+itecheckwrap(ip, sp)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+{
+       if (++ip->curx == ip->cols) {
+               ip->curx = 0;
+               clr_attr(ip, ATTR_INV);
+               if (++ip->cury == ip->rows) {
+                       --ip->cury;
+                       (*sp->ite_scroll)(ip, 1, 0, 1, SCROLL_UP);
+                       ite_clrtoeol(ip, sp, ip->cury, 0);
+                       return;
+               }
+       }
+       (*sp->ite_cursor)(ip, MOVE_CURSOR);
+}
+
+ite_dchar(ip, sp)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+{
+       (*sp->ite_scroll)(ip, ip->cury, ip->curx + 1, 1, SCROLL_LEFT);
+       attrmov(ip, ip->cury, ip->curx + 1, ip->cury, ip->curx,
+               1, ip->cols - ip->curx - 1);
+       attrclr(ip, ip->cury, ip->cols - 1, 1, 1);
+       (*sp->ite_putc)(ip, ' ', ip->cury, ip->cols - 1, ATTR_NOR);
+       (*sp->ite_cursor)(ip, DRAW_CURSOR);
+}
+
+ite_ichar(ip, sp)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+{
+       (*sp->ite_scroll)(ip, ip->cury, ip->curx, 1, SCROLL_RIGHT);
+       attrmov(ip, ip->cury, ip->curx, ip->cury, ip->curx + 1,
+               1, ip->cols - ip->curx - 1);
+       attrclr(ip, ip->cury, ip->curx, 1, 1);
+       (*sp->ite_putc)(ip, ' ', ip->cury, ip->curx, ATTR_NOR);
+       (*sp->ite_cursor)(ip, DRAW_CURSOR);
+}
+
+ite_dline(ip, sp)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+{
+       (*sp->ite_scroll)(ip, ip->cury + 1, 0, 1, SCROLL_UP);
+       attrmov(ip, ip->cury + 1, 0, ip->cury, 0,
+               ip->rows - ip->cury - 1, ip->cols);
+       ite_clrtoeol(ip, sp, ip->rows - 1, 0);
+}
+
+ite_iline(ip, sp)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+{
+       (*sp->ite_scroll)(ip, ip->cury, 0, 1, SCROLL_DOWN);
+       attrmov(ip, ip->cury, 0, ip->cury + 1, 0,
+               ip->rows - ip->cury - 1, ip->cols);
+       ite_clrtoeol(ip, sp, ip->cury, 0);
+}
+
+ite_clrtoeol(ip, sp, y, x)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+     register int y, x;
+{
+       (*sp->ite_clear)(ip, y, x, 1, ip->cols - x);
+       attrclr(ip, y, x, 1, ip->cols - x);
+       (*sp->ite_cursor)(ip, DRAW_CURSOR);
+}
+
+ite_clrtoeos(ip, sp)
+     register struct ite_softc *ip;
+     register struct itesw *sp;
+{
+       (*sp->ite_clear)(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols);
+       attrclr(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols);
+       (*sp->ite_cursor)(ip, DRAW_CURSOR);
+}
+
+/*
+ * Console functions
+ */
+#include "machine/cons.h"
+#include "grfioctl.h"
+#include "grfvar.h"
+
+#ifdef DEBUG
+/*
+ * Minimum ITE number at which to start looking for a console.
+ * Setting to 0 will do normal search, 1 will skip first ITE device,
+ * NITE will skip ITEs and use serial port.
+ */
+int    whichconsole = 0;
+#endif
+
+itecnprobe(cp)
+       struct consdev *cp;
+{
+       register struct ite_softc *ip;
+       int i, maj, unit, pri;
+       extern int iteopen();
+
+       /* locate the major number */
+       for (maj = 0; maj < nchrdev; maj++)
+               if (cdevsw[maj].d_open == iteopen)
+                       break;
+
+       /* urk! */
+       grfconfig();
+
+       /* check all the individual displays and find the best */
+       unit = -1;
+       pri = CN_DEAD;
+       for (i = 0; i < NITE; i++) {
+               struct grf_softc *gp = &grf_softc[i];
+
+               ip = &ite_softc[i];
+               if ((gp->g_flags & GF_ALIVE) == 0)
+                       continue;
+               ip->flags = (ITE_ALIVE|ITE_CONSOLE);
+
+               /* XXX - we need to do something about mapping these */
+               switch (gp->g_type) {
+
+               case GT_TOPCAT:
+               case GT_LRCATSEYE:
+               case GT_HRCCATSEYE:
+               case GT_HRMCATSEYE:
+                       ip->type = ITE_TOPCAT;
+                       break;
+               case GT_GATORBOX:
+                       ip->type = ITE_GATORBOX;
+                       break;
+               case GT_RENAISSANCE:
+                       ip->type = ITE_RENAISSANCE;
+                       break;
+               case GT_DAVINCI:
+                       ip->type = ITE_DAVINCI;
+                       break;
+               }
+#ifdef DEBUG
+               if (i < whichconsole)
+                       continue;
+#endif
+               if ((int)gp->g_display.gd_regaddr == GRFIADDR) {
+                       pri = CN_INTERNAL;
+                       unit = i;
+               } else if (unit < 0) {
+                       pri = CN_NORMAL;
+                       unit = i;
+               }
+       }
+
+       /* initialize required fields */
+       cp->cn_dev = makedev(maj, unit);
+       cp->cn_tp = &ite_tty[unit];
+       cp->cn_pri = pri;
+}
+
+itecninit(cp)
+       struct consdev *cp;
+{
+       int unit = UNIT(cp->cn_dev);
+       struct ite_softc *ip = &ite_softc[unit];
+
+       ip->attrbuf = console_attributes;
+       iteinit(cp->cn_dev);
+       ip->flags |= (ITE_ACTIVE|ITE_ISCONS);
+       kbd_tty = &ite_tty[unit];
+}
+
+/*ARGSUSED*/
+itecngetc(dev)
+       dev_t dev;
+{
+       register int c;
+       int stat;
+
+       c = kbdgetc(&stat);
+       switch ((stat >> KBD_SSHIFT) & KBD_SMASK) {
+       case KBD_SHIFT:
+               c = kbd_shiftmap[c & KBD_CHARMASK];
+               break;
+       case KBD_CTRL:
+               c = kbd_ctrlmap[c & KBD_CHARMASK];
+               break;
+       case KBD_KEY:
+               c = kbd_keymap[c & KBD_CHARMASK];
+               break;
+       default:
+               c = 0;
+               break;
+       }
+       return(c);
+}
+
+itecnputc(dev, c)
+       dev_t dev;
+       int c;
+{
+       static int paniced = 0;
+       struct ite_softc *ip = &ite_softc[UNIT(dev)];
+       extern char *panicstr;
+
+       if (panicstr && !paniced &&
+           (ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) {
+               (void) iteon(dev, 3);
+               paniced = 1;
+       }
+       iteputchar(c, dev);
+}
+#endif
diff --git a/usr/src/sys/hp/dev/ite_subr.c b/usr/src/sys/hp/dev/ite_subr.c
new file mode 100644 (file)
index 0000000..1c543b4
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: ite_subr.c 1.3 89/04/11$
+ *
+ *     @(#)ite_subr.c  7.1 (Berkeley) %G%
+ */
+
+#include "ite.h"
+#if NITE > 0
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+
+#include "itevar.h"
+#include "itereg.h"
+
+#include "machine/cpu.h"
+
+ite_devinfo(ip)
+       struct ite_softc *ip;
+{
+       struct fontinfo *fi;
+       struct font *fd;
+
+       fi = (struct fontinfo *) ((*FONTROM << 8 | *(FONTROM + 2)) + REGADDR);
+       fd = (struct font *) ((fi->haddr << 8 | fi->laddr) + REGADDR);
+
+       ip->ftheight = fd->fh;
+       ip->ftwidth  = fd->fw;
+       ip->fbwidth  = ITEREGS->fbwidth_h << 8 | ITEREGS->fbwidth_l;
+       ip->fbheight = ITEREGS->fbheight_h << 8 | ITEREGS->fbheight_l;
+       ip->dwidth   = ITEREGS->dispwidth_h << 8 | ITEREGS->dispwidth_l;
+       ip->dheight  = ITEREGS->dispheight_h << 8 | ITEREGS->dispheight_l;
+       ip->rows     = ip->dheight / ip->ftheight;
+       ip->cols     = ip->dwidth / ip->ftwidth;
+
+       if (ip->fbwidth > ip->dwidth) {
+               /*
+                * Stuff goes to right of display.
+                */
+               ip->fontx    = ip->dwidth;
+               ip->fonty    = 0;
+               ip->cpl      = (ip->fbwidth - ip->dwidth) / ip->ftwidth;
+               ip->cblankx  = ip->dwidth;
+               ip->cblanky  = ip->fonty + ((128 / ip->cpl) +1) * ip->ftheight;
+       }
+       else {
+               /*
+                * Stuff goes below the display.
+                */
+               ip->fontx   = 0;
+               ip->fonty   = ip->dheight;
+               ip->cpl     = ip->fbwidth / ip->ftwidth;
+               ip->cblankx = 0;
+               ip->cblanky = ip->fonty + ((128 / ip->cpl) + 1) * ip->ftheight;
+       }
+}
+
+ite_fontinit(ip)
+       register struct ite_softc *ip;
+{
+       struct fontinfo *fi;
+       struct font *fd;
+       register u_char *fbmem, *dp;
+       register int bn;
+       int c, l, b;
+
+       fi = (struct fontinfo *) ((*FONTROM << 8 | *(FONTROM + 2)) + REGADDR);
+       fd = (struct font *) ((fi->haddr << 8 | fi->laddr) + REGADDR);
+
+       dp = fd->data;
+
+       for (c = 0; c < 128; c++) {
+               fbmem = (u_char *) FBBASE +
+                       (ip->fonty + (c / ip->cpl) * ip->ftheight) *
+                       ip->fbwidth;
+               fbmem += ip->fontx + (c % ip->cpl) * ip->ftwidth;
+               for (l = 0; l < ip->ftheight; l++) {
+                       bn = 7;
+                       for (b = 0; b < ip->ftwidth; b++) {
+                               if ((1 << bn) & *dp)
+                                       *fbmem++ = 1;
+                               else
+                                       *fbmem++ = 0;
+                               if (--bn < 0) {
+                                       bn = 7;
+                                       dp += 2;
+                               }
+                       }
+                       if (bn < 7)
+                               dp += 2;
+                       fbmem -= ip->ftwidth;
+                       fbmem += ip->fbwidth;
+               }
+       }
+
+}
+#endif
diff --git a/usr/src/sys/hp/dev/iteioctl.h b/usr/src/sys/hp/dev/iteioctl.h
new file mode 100644 (file)
index 0000000..0dd83a0
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: iteioctl.h 1.2 88/05/24$
+ *
+ *     @(#)iteioctl.h  7.1 (Berkeley) %G%
+ */
+
+#define ITESWITCH _IOW('Z',0x69, int)  /* XXX */
diff --git a/usr/src/sys/hp/dev/itereg.h b/usr/src/sys/hp/dev/itereg.h
new file mode 100644 (file)
index 0000000..9cf86ba
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: itereg.h 1.2 89/08/25$
+ *
+ *     @(#)itereg.h    7.1 (Berkeley) %G%
+ */
+
+#define REGADDR                ip->regbase
+#define FBBASE         ((volatile u_char *)ip->fbbase)
+#define        FONTROM         ((u_char *)(REGADDR+0x3B))
+#define ITEREGS                ((struct iteregs *)(REGADDR))
+
+/*
+ * All of the HP displays use the same font ROM setup. These structures
+ * are used to get at them.
+ */
+
+struct iteregs {
+       u_short reset;
+       u_short interrupt;
+       u_char  :8,
+               fbwidth_h,
+               :8,
+               fbwidth_l,
+               :8,
+               fbheight_h,
+               :8,
+               fbheight_l,
+               :8,
+               dispwidth_h,
+               :8,
+               dispwidth_l,
+               :8,
+               dispheight_h,
+               :8,
+               dispheight_l;
+};
+
+struct fontinfo {
+       u_char  nfonts, :8,
+               fontid, :8,
+               haddr,  :8,
+               laddr,  :8;
+};
+
+struct font {
+       u_char  fh,     :8,
+               fw;
+       u_char  pad[7],
+               data[256];
+};
+
+#define draw_cursor(ip) { \
+       WINDOWMOVER(ip, ip->cblanky, ip->cblankx, \
+                   ip->cury * ip->ftheight, \
+                   ip->curx * ip->ftwidth, \
+                   ip->ftheight, ip->ftwidth, RR_XOR); \
+        ip->cursorx = ip->curx; \
+       ip->cursory = ip->cury; }
+
+#define erase_cursor(ip) \
+       WINDOWMOVER(ip, ip->cblanky, ip->cblankx, \
+                   ip->cursory * ip->ftheight, \
+                   ip->cursorx * ip->ftwidth, \
+                   ip->ftheight, ip->ftwidth, RR_XOR);
diff --git a/usr/src/sys/hp/dev/itevar.h b/usr/src/sys/hp/dev/itevar.h
new file mode 100644 (file)
index 0000000..a6a992e
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: itevar.h 1.13 89/02/27$
+ *
+ *     @(#)itevar.h    7.1 (Berkeley) %G%
+ */
+
+#define UNIT(dev)       minor(dev)
+
+struct itesw {
+       int     (*ite_init)();
+       int     (*ite_deinit)();
+       int     (*ite_clear)();
+       int     (*ite_putc)();
+       int     (*ite_cursor)();
+       int     (*ite_scroll)();
+};
+
+struct ite_softc {
+       int     flags;
+       int     type;
+       caddr_t regbase, fbbase;
+       short   curx, cury;
+       short   cursorx, cursory;
+       short   cblankx, cblanky;
+       short   rows, cols;
+       short   cpl;
+       short   dheight, dwidth;
+       short   fbheight, fbwidth;
+       short   ftheight, ftwidth;
+       short   fontx, fonty;
+       short   attribute;
+       u_char  *attrbuf;
+       short   planemask;
+       short   pos;
+       char    imode, escape, fpd, hold;
+};
+
+/* Flags */
+#define ITE_ALIVE      0x01    /* hardware exists */
+#define ITE_INITED     0x02    /* device has been initialized */
+#define ITE_CONSOLE    0x04    /* device can be console */
+#define ITE_ISCONS     0x08    /* device is console */
+#define ITE_ACTIVE     0x10    /* device is being used as ITE */
+#define ITE_INGRF      0x20    /* device in use as non-ITE */
+
+/* Types - indices into itesw */
+#define        ITE_TOPCAT      0
+#define        ITE_GATORBOX    1
+#define        ITE_RENAISSANCE 2
+#define ITE_DAVINCI    3
+
+#define attrloc(ip, y, x) \
+       (ip->attrbuf + ((y) * ip->cols) + (x))
+
+#define attrclr(ip, sy, sx, h, w) \
+       bzero(ip->attrbuf + ((sy) * ip->cols) + (sx), (h) * (w))
+  
+#define attrmov(ip, sy, sx, dy, dx, h, w) \
+       bcopy(ip->attrbuf + ((sy) * ip->cols) + (sx), \
+             ip->attrbuf + ((dy) * ip->cols) + (dx), \
+             (h) * (w))
+
+#define attrtest(ip, attr) \
+       ((* (u_char *) attrloc(ip, ip->cury, ip->curx)) & attr)
+
+#define attrset(ip, attr) \
+       ((* (u_char *) attrloc(ip, ip->cury, ip->curx)) = attr)
+  
+/*
+ * X and Y location of character 'c' in the framebuffer, in pixels.
+ */
+#define        charX(ip,c)     \
+       (((c) % (ip)->cpl) * (ip)->ftwidth + (ip)->fontx)
+
+#define        charY(ip,c)     \
+       (((c) / (ip)->cpl) * (ip)->ftheight + (ip)->fonty)
+
+/* Character attributes */
+#define ATTR_NOR        0x0             /* normal */
+#define        ATTR_INV        0x1             /* inverse */
+#define        ATTR_UL         0x2             /* underline */
+#define ATTR_ALL       (ATTR_INV | ATTR_UL)
+
+/* Keyboard attributes */
+#define ATTR_KPAD      0x4             /* keypad transmit */
+  
+/* Replacement Rules */
+#define RR_CLEAR               0x0
+#define RR_COPY                        0x3
+#define RR_XOR                 0x6
+#define RR_COPYINVERTED        0xc
+
+#define SCROLL_UP      0x01
+#define SCROLL_DOWN    0x02
+#define SCROLL_LEFT    0x03
+#define SCROLL_RIGHT   0x04
+#define DRAW_CURSOR    0x05
+#define ERASE_CURSOR    0x06
+#define MOVE_CURSOR    0x07
+
+#define KBD_SSHIFT     4               /* bits to shift status */
+#define        KBD_CHARMASK    0x7F
+
+/* keyboard status */
+#define        KBD_SMASK       0xF             /* service request status mask */
+#define        KBD_CTRLSHIFT   0x8             /* key + CTRL + SHIFT */
+#define        KBD_CTRL        0x9             /* key + CTRL */
+#define        KBD_SHIFT       0xA             /* key + SHIFT */
+#define        KBD_KEY         0xB             /* key only */
+
+#define KBD_CAPSLOCK    0x18
+
+#define KBD_EXT_LEFT_DOWN     0x12
+#define KBD_EXT_LEFT_UP       0x92
+#define KBD_EXT_RIGHT_DOWN    0x13
+#define KBD_EXT_RIGHT_UP      0x93
+
+#define        TABSIZE         8
+#define        TABEND(u)       (ite_tty[u].t_winsize.ws_col - TABSIZE)
+
+#ifdef KERNEL
+extern struct ite_softc ite_softc[];
+#endif
diff --git a/usr/src/sys/hp/dev/kbdmap.h b/usr/src/sys/hp/dev/kbdmap.h
new file mode 100644 (file)
index 0000000..bf29bd0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)kbdmap.h    7.1 (Berkeley) %G%
+ */
+
+#define        ESC     '\033'
+#define        DEL     '\177'
+
+struct kbdmap {
+       int     kbd_code;
+       char    *kbd_desc;
+       char    *kbd_keymap;
+       char    *kbd_shiftmap;
+       char    *kbd_ctrlmap;
+       char    *kbd_ctrlshiftmap;
+       char    **kbd_stringmap;
+};
+
+/* kbd_code */
+#define KBD_SPECIAL    0x00            /* user defined */
+#define KBD_US         0x1F            /* US ASCII */
+#define KBD_UK         0x17            /* United Kingdom */
+
+#define KBD_DEFAULT    KBD_US          /* default type */
+
+#ifdef KERNEL
+/* XXX: ITE interface */
+char   *kbd_keymap;
+char   *kbd_shiftmap;
+char   *kbd_ctrlmap;
+char   *kbd_ctrlshiftmap;
+char   **kbd_stringmap;
+
+extern struct kbdmap kbd_map[];
+#endif
diff --git a/usr/src/sys/hp300/dev/ct.c b/usr/src/sys/hp300/dev/ct.c
new file mode 100644 (file)
index 0000000..c5b6f95
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ct.c        7.1 (Berkeley) %G%
+ */
+
+#include "ct.h"
+#if NCT > 0
+/*
+ * CS80 cartridge tape driver (9144, 88140, 9145)
+ *
+ * Reminder:
+ *     C_CC bit (character count option) when used in the CS/80 command
+ *     'set options' will cause the tape not to stream.
+ *
+ * TODO:
+ *     make filesystem compatible
+ *     make block mode work according to mtio(4) spec. (if possible)
+ *     merge with cs80 disk driver
+ *     finish support of 9145
+ */
+
+#include "param.h"
+#include "buf.h"
+#include "ioctl.h"
+#include "mtio.h"
+#include "errno.h"
+#include "ctreg.h"
+#include "device.h"
+#include "user.h"
+#include "tty.h"
+#include "proc.h"
+
+/* number of eof marks to remember */
+#define EOFS   128
+
+int    ctinit(), ctstart(), ctgo(), ctintr();
+struct driver ctdriver = {
+       ctinit, "ct", ctstart, ctgo, ctintr,
+};
+
+struct ct_softc {
+       struct  hp_device *sc_hd;
+       struct  ct_iocmd sc_ioc;
+       struct  ct_rscmd sc_rsc;
+       struct  ct_stat sc_stat;
+       struct  ct_ssmcmd sc_ssmc;
+       struct  ct_srcmd sc_src;
+       struct  ct_soptcmd sc_soptc;
+       struct  ct_ulcmd sc_ul;
+       struct  ct_wfmcmd sc_wfm;
+       struct  ct_clearcmd sc_clear;
+       struct  buf *sc_bp;
+       int     sc_blkno;
+       int     sc_cmd;
+       int     sc_resid;
+       char    *sc_addr;
+       int     sc_flags;
+       short   sc_type;
+       short   sc_punit;
+       caddr_t sc_ctty;
+       struct  devqueue sc_dq;
+       int     sc_eofp;
+       int     sc_eofs[EOFS];
+} ct_softc[NCT];
+
+/* flags */
+#define        CTF_OPEN        0x01
+#define        CTF_ALIVE       0x02
+#define        CTF_WRT         0x04
+#define        CTF_CMD         0x08
+#define        CTF_IO          0x10
+#define        CTF_BEOF        0x20
+#define        CTF_AEOF        0x40
+#define        CTF_EOT         0x80
+#define        CTF_STATWAIT    0x100
+#define CTF_CANSTREAM  0x200
+#define        CTF_WRTTN       0x400
+
+struct ctinfo {
+       short   hwid;
+       short   punit;
+       char    *desc;
+} ctinfo[] = {
+       CT7946ID,       1,      "7946A",
+       CT7912PID,      1,      "7912P",
+       CT7914PID,      1,      "7914P",
+       CT9144ID,       0,      "9144",
+       CT9145ID,       0,      "9145",
+};
+int    nctinfo = sizeof(ctinfo) / sizeof(ctinfo[0]);
+
+struct buf cttab[NCT];
+struct buf ctbuf[NCT];
+
+#define        CT_NOREW        4
+#define        CT_STREAM       8
+#define        UNIT(x)         (minor(x) & 3)
+#define        ctpunit(x)      ((x) & 7)
+
+#ifdef DEBUG
+int ctdebug = 0;
+#define CDB_FILES      0x01
+#define CT_BSF         0x02
+#endif
+
+ctinit(hd)
+       register struct hp_device *hd;
+{
+       register struct ct_softc *sc = &ct_softc[hd->hp_unit];
+
+       sc->sc_hd = hd;
+       sc->sc_punit = ctpunit(hd->hp_flags);
+       if (ctident(sc, hd) < 0)
+               return(0);
+       ctreset(sc, hd);
+       sc->sc_dq.dq_ctlr = hd->hp_ctlr;
+       sc->sc_dq.dq_unit = hd->hp_unit;
+       sc->sc_dq.dq_slave = hd->hp_slave;
+       sc->sc_dq.dq_driver = &ctdriver;
+       sc->sc_flags |= CTF_ALIVE;
+       return(1);
+}
+
+ctident(sc, hd)
+       register struct ct_softc *sc;
+       register struct hp_device *hd;
+{
+       struct ct_describe desc;
+       u_char stat, cmd[3];
+       char name[7];
+       int id, i;
+
+       /*
+        * Read device id and verify that:
+        * 1. It is a CS80 device
+        * 2. It is one of our recognized tape devices
+        * 3. It has the proper physical unit number
+        */
+       id = hpibid(hd->hp_ctlr, hd->hp_slave);
+       if ((id & 0x200) == 0)
+               return(-1);
+       for (i = 0; i < nctinfo; i++)
+               if (id == ctinfo[i].hwid)
+                       break;
+       if (i == nctinfo || sc->sc_punit != ctinfo[i].punit)
+               return(-1);
+       id = i;
+
+       /*
+        * Collect device description.
+        * Right now we only need this to differentiate 7945 from 7946.
+        * Note that we always issue the describe command to unit 0.
+        */
+       cmd[0] = C_SUNIT(0);
+       cmd[1] = C_SVOL(0);
+       cmd[2] = C_DESC;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, cmd, sizeof(cmd));
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_EXEC, &desc, 37);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+       bzero(name, sizeof(name));
+       if (!stat) {
+               register int n = desc.d_name;
+               for (i = 5; i >= 0; i--) {
+                       name[i] = (n & 0xf) + '0';
+                       n >>= 4;
+               }
+       }
+       switch (ctinfo[id].hwid) {
+       case CT7946ID:
+               if (bcmp(name, "079450", 6) == 0)
+                       return(-1);             /* not really a 7946 */
+               /* fall into... */
+       case CT9144ID:
+       case CT9145ID:
+               sc->sc_type = CT9144;
+               sc->sc_flags |= CTF_CANSTREAM;
+               break;
+
+       case CT7912PID:
+       case CT7914PID:
+               sc->sc_type = CT88140;
+               break;
+       }
+       printf("ct%d: %s %stape\n", hd->hp_unit, ctinfo[id].desc,
+              (sc->sc_flags & CTF_CANSTREAM) ? "streaming " : " ");
+       return(id);
+}
+
+ctreset(sc, hd)
+       register struct ct_softc *sc;
+       register struct hp_device *hd;
+{
+       u_char stat;
+
+       sc->sc_clear.unit = C_SUNIT(sc->sc_punit);
+       sc->sc_clear.cmd = C_CLEAR;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &sc->sc_clear,
+               sizeof(sc->sc_clear));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+       sc->sc_src.unit = C_SUNIT(CTCTLR);
+       sc->sc_src.nop = C_NOP;
+       sc->sc_src.cmd = C_SREL;
+       sc->sc_src.param = C_REL;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &sc->sc_src,
+               sizeof(sc->sc_src));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+       sc->sc_ssmc.unit = C_SUNIT(sc->sc_punit);
+       sc->sc_ssmc.cmd = C_SSM;
+       sc->sc_ssmc.refm = REF_MASK;
+       sc->sc_ssmc.fefm = FEF_MASK;
+       sc->sc_ssmc.aefm = AEF_MASK;
+       sc->sc_ssmc.iefm = IEF_MASK;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &sc->sc_ssmc,
+               sizeof(sc->sc_ssmc));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+       sc->sc_soptc.unit = C_SUNIT(sc->sc_punit);
+       sc->sc_soptc.nop = C_NOP;
+       sc->sc_soptc.cmd = C_SOPT;
+       sc->sc_soptc.opt = C_SPAR;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &sc->sc_soptc,
+               sizeof(sc->sc_soptc));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+}
+
+/*ARGSUSED*/
+ctopen(dev, flag)
+       dev_t dev;
+{
+       register struct ct_softc *sc = &ct_softc[UNIT(dev)];
+       u_char stat;
+       int cc;
+
+       if (UNIT(dev) >= NCT || (sc->sc_flags & CTF_ALIVE) == 0)
+               return(ENXIO);
+       if (sc->sc_flags & CTF_OPEN)
+               return(EBUSY);
+       sc->sc_soptc.unit = C_SUNIT(sc->sc_punit);
+       sc->sc_soptc.nop = C_NOP;
+       sc->sc_soptc.cmd = C_SOPT;
+       if ((dev & CT_STREAM) && (sc->sc_flags & CTF_CANSTREAM))
+               sc->sc_soptc.opt = C_SPAR | C_IMRPT;
+       else
+               sc->sc_soptc.opt = C_SPAR;
+       /* 
+        * Check the return of hpibsend() and hpibswait().
+        * Drive could be loading/unloading a tape. If not checked,
+        * driver hangs. 
+        */
+       cc = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                     C_CMD, &sc->sc_soptc, sizeof(sc->sc_soptc));
+       if (cc != sizeof(sc->sc_soptc))
+               return(EBUSY);
+       hpibswait(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave);
+       cc = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_QSTAT, 
+                     &stat, sizeof(stat));
+       if (cc != sizeof(stat))
+               return(EBUSY);
+       sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ? 
+                       u.u_procp->p_session->s_ttyvp : 0);
+       sc->sc_flags |= CTF_OPEN;
+       return(0);
+}
+
+/*ARGSUSED*/
+ctclose(dev, flag)
+       dev_t dev;
+{
+       register struct ct_softc *sc = &ct_softc[UNIT(dev)];
+
+       if ((sc->sc_flags & (CTF_WRT|CTF_WRTTN)) == (CTF_WRT|CTF_WRTTN) &&
+           (sc->sc_flags & CTF_EOT) == 0 ) { /* XXX return error if EOT ?? */
+               ctcommand(dev, MTWEOF, 2);
+               ctcommand(dev, MTBSR, 1);
+               if (sc->sc_eofp == EOFS - 1)
+                       sc->sc_eofs[EOFS - 1]--;
+               else
+                       sc->sc_eofp--;
+#ifdef DEBUG
+               if(ctdebug & CT_BSF)
+                       printf("ct%d: ctclose backup eofs prt %d blk %d\n",
+                              UNIT(dev), sc->sc_eofp, sc->sc_eofs[sc->sc_eofp]);
+#endif
+       }
+       if ((minor(dev) & CT_NOREW) == 0)
+               ctcommand(dev, MTREW, 1);
+       sc->sc_flags &= ~(CTF_OPEN | CTF_WRT | CTF_WRTTN);
+       sc->sc_ctty = NULL;
+#ifdef DEBUG
+       if (ctdebug & CDB_FILES)
+               printf("ctclose: flags %x\n", sc->sc_flags);
+#endif
+       return(0);      /* XXX */
+}
+
+ctcommand(dev, cmd, cnt)
+       dev_t dev;
+       register int cnt;
+{
+       register struct ct_softc *sc = &ct_softc[UNIT(dev)];
+       register struct buf *bp = &ctbuf[UNIT(dev)];
+       register struct buf *nbp = 0;
+
+       if (cmd == MTBSF && sc->sc_eofp == EOFS - 1) {
+               cnt = sc->sc_eofs[EOFS - 1] - cnt;
+               ctcommand(dev, MTREW, 1);
+               ctcommand(dev, MTFSF, cnt);
+               cnt = 2;
+               cmd = MTBSR;
+       }
+
+       if (cmd == MTBSF && sc->sc_eofp - cnt < 0) {
+               cnt = 1;
+               cmd = MTREW;
+       }
+
+       sc->sc_flags |= CTF_CMD;
+       sc->sc_bp = bp;
+       sc->sc_cmd = cmd;
+       bp->b_dev = dev;
+       if (cmd == MTFSF) {
+               nbp = (struct buf *)geteblk(MAXBSIZE);
+               bp->b_un.b_addr = nbp->b_un.b_addr;
+               bp->b_bcount = MAXBSIZE;
+       }
+again:
+       bp->b_flags = B_BUSY;
+       if (cmd == MTBSF) {
+               sc->sc_blkno = sc->sc_eofs[sc->sc_eofp];
+               sc->sc_eofp--;
+#ifdef DEBUG
+               if (ctdebug & CT_BSF)
+                       printf("ct%d: backup eof pos %d blk %d\n",
+                              UNIT(dev), sc->sc_eofp, 
+                              sc->sc_eofs[sc->sc_eofp]);
+#endif
+       }
+       ctstrategy(bp);
+       iowait(bp);
+       if (--cnt > 0)
+               goto again;
+       bp->b_flags = 0;
+       sc->sc_flags &= ~CTF_CMD;
+       if (nbp)
+               brelse(nbp);
+}
+
+ctstrategy(bp)
+       register struct buf *bp;
+{
+       register struct buf *dp;
+       register int s, unit;
+
+       unit = UNIT(bp->b_dev);
+       dp = &cttab[unit];
+       bp->av_forw = NULL;
+       s = splbio();
+       if (dp->b_actf == NULL)
+               dp->b_actf = bp;
+       else
+               dp->b_actl->av_forw = bp;
+       dp->b_actl = bp;
+       if (dp->b_active == 0) {
+               dp->b_active = 1;
+               ctustart(unit);
+       }
+       splx(s);
+}
+
+ctustart(unit)
+       register int unit;
+{
+       register struct ct_softc *sc = &ct_softc[unit];
+       register struct buf *bp;
+
+       bp = cttab[unit].b_actf;
+       sc->sc_addr = bp->b_un.b_addr;
+       sc->sc_resid = bp->b_bcount;
+       if (hpibreq(&sc->sc_dq))
+               ctstart(unit);
+}
+
+ctstart(unit)
+       register int unit;
+{
+       register struct ct_softc *sc = &ct_softc[unit];
+       register struct buf *bp;
+       register int i;
+
+       bp = cttab[unit].b_actf;
+again:
+       if ((sc->sc_flags & CTF_CMD) && sc->sc_bp == bp) {
+               switch(sc->sc_cmd) {
+
+               case MTFSF:
+                       bp->b_flags |= B_READ;
+                       goto mustio;
+
+               case MTBSF:
+                       goto gotaddr;
+
+               case MTOFFL:
+                       sc->sc_blkno = 0;
+                       sc->sc_ul.unit = C_SUNIT(sc->sc_punit);
+                       sc->sc_ul.cmd = C_UNLOAD;
+                       hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                               C_CMD, &sc->sc_ul, sizeof(sc->sc_ul));
+                       break;
+
+               case MTWEOF:
+                       sc->sc_blkno++;
+                       sc->sc_flags |= CTF_WRT;
+                       sc->sc_wfm.unit = C_SUNIT(sc->sc_punit);
+                       sc->sc_wfm.cmd = C_WFM;
+                       hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                               C_CMD, &sc->sc_wfm, sizeof(sc->sc_wfm));
+                       ctaddeof(unit);
+                       break;
+
+               case MTBSR:
+                       sc->sc_blkno--;
+                       goto gotaddr;
+
+               case MTFSR:
+                       sc->sc_blkno++;
+                       goto gotaddr;
+
+               case MTREW:
+                       sc->sc_blkno = 0;
+#ifdef DEBUG
+                       if(ctdebug & CT_BSF)
+                               printf("ct%d: clearing eofs\n", unit);
+#endif
+                       for (i=0; i<EOFS; i++)
+                               sc->sc_eofs[i] = 0;
+                       sc->sc_eofp = 0;
+
+gotaddr:
+                       sc->sc_ioc.saddr = C_SADDR;
+                       sc->sc_ioc.addr0 = 0;
+                       sc->sc_ioc.addr = sc->sc_blkno;
+                       sc->sc_ioc.unit = C_SUNIT(sc->sc_punit);
+                       sc->sc_ioc.nop2 = C_NOP;
+                       sc->sc_ioc.slen = C_SLEN;
+                       sc->sc_ioc.len = 0;
+                       sc->sc_ioc.nop3 = C_NOP;
+                       sc->sc_ioc.cmd = C_READ;
+                       hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                               C_CMD, &sc->sc_ioc, sizeof(sc->sc_ioc));
+                       break;
+               }
+       }
+       else {
+mustio:
+               if ((bp->b_flags & B_READ) &&
+                   sc->sc_flags & (CTF_BEOF|CTF_EOT)) {
+#ifdef DEBUG
+                       if (ctdebug & CDB_FILES)
+                               printf("ctstart: before flags %x\n", sc->sc_flags);
+#endif
+                       if (sc->sc_flags & CTF_BEOF) {
+                               sc->sc_flags &= ~CTF_BEOF;
+                               sc->sc_flags |= CTF_AEOF;
+#ifdef DEBUG
+                               if (ctdebug & CDB_FILES)
+                                       printf("ctstart: after flags %x\n", sc->sc_flags);
+#endif
+                       }
+                       bp->b_resid = bp->b_bcount;
+                       iodone(bp);
+                       hpibfree(&sc->sc_dq);
+                       cttab[unit].b_actf = bp = bp->av_forw;
+                       if (bp == NULL) {
+                               cttab[unit].b_active = 0;
+                               return;
+                       }
+                       sc->sc_addr = bp->b_un.b_addr;
+                       sc->sc_resid = bp->b_bcount;
+                       if (hpibreq(&sc->sc_dq))
+                               goto again;
+                       return;
+               }                       
+               sc->sc_flags |= CTF_IO;
+               sc->sc_ioc.unit = C_SUNIT(sc->sc_punit);
+               sc->sc_ioc.saddr = C_SADDR;
+               sc->sc_ioc.addr0 = 0;
+               sc->sc_ioc.addr = sc->sc_blkno;
+               sc->sc_ioc.nop2 = C_NOP;
+               sc->sc_ioc.slen = C_SLEN;
+               sc->sc_ioc.len = sc->sc_resid;
+               sc->sc_ioc.nop3 = C_NOP;
+               if (bp->b_flags & B_READ)
+                       sc->sc_ioc.cmd = C_READ;
+               else {
+                       sc->sc_ioc.cmd = C_WRITE;
+                       sc->sc_flags |= (CTF_WRT | CTF_WRTTN);
+               }
+               hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_CMD,
+                       &sc->sc_ioc, sizeof(sc->sc_ioc));
+       }
+       hpibawait(sc->sc_hd->hp_ctlr);
+}
+
+ctgo(unit)
+       register int unit;
+{
+       register struct ct_softc *sc = &ct_softc[unit];
+       register struct buf *bp;
+
+       bp = cttab[unit].b_actf;
+       hpibgo(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_EXEC,
+               sc->sc_addr, sc->sc_resid, bp->b_flags & B_READ);
+}
+
+/*
+ * Hideous grue to handle EOF/EOT (mostly for reads)
+ */
+cteof(sc, bp)
+       register struct ct_softc *sc;
+       register struct buf *bp;
+{
+       long blks;
+
+       /*
+        * EOT on a write is an error.
+        */
+       if ((bp->b_flags & B_READ) == 0) {
+               bp->b_resid = bp->b_bcount;
+               bp->b_flags |= B_ERROR;
+               bp->b_error = ENOSPC;
+               sc->sc_flags |= CTF_EOT;
+               return;
+       }
+       /*
+        * Use returned block position to determine how many blocks
+        * we really read and update b_resid.
+        */
+       blks = sc->sc_stat.c_blk - sc->sc_blkno - 1;
+#ifdef DEBUG
+       if (ctdebug & CDB_FILES)
+               printf("cteof: bc %d oblk %d nblk %d read %d, resid %d\n",
+                      bp->b_bcount, sc->sc_blkno, sc->sc_stat.c_blk,
+                      blks, bp->b_bcount - CTKTOB(blks));
+#endif
+       if (blks == -1) { /* 9145 on EOF does not change sc_stat.c_blk */
+               blks = 0;
+               sc->sc_blkno++;
+       }
+       else {
+               sc->sc_blkno = sc->sc_stat.c_blk;
+       }
+       bp->b_resid = bp->b_bcount - CTKTOB(blks);
+       /*
+        * If we are at physical EOV or were after an EOF,
+        * we are now at logical EOT.
+        */
+       if ((sc->sc_stat.c_aef & AEF_EOV) ||
+           (sc->sc_flags & CTF_AEOF)) {
+               sc->sc_flags |= CTF_EOT;
+               sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF);
+       }
+       /*
+        * If we were before an EOF or we have just completed a FSF,
+        * we are now after EOF.
+        */
+       else if ((sc->sc_flags & CTF_BEOF) ||
+                (sc->sc_flags & CTF_CMD) && sc->sc_cmd == MTFSF) {
+               sc->sc_flags |= CTF_AEOF;
+               sc->sc_flags &= ~CTF_BEOF;
+       }
+       /*
+        * Otherwise if we read something we are now before EOF
+        * (and no longer after EOF).
+        */
+       else if (blks) {
+               sc->sc_flags |= CTF_BEOF;
+               sc->sc_flags &= ~CTF_AEOF;
+       }
+       /*
+        * Finally, if we didn't read anything we just passed an EOF
+        */
+       else
+               sc->sc_flags |= CTF_AEOF;
+#ifdef DEBUG
+       if (ctdebug & CDB_FILES)
+               printf("cteof: leaving flags %x\n", sc->sc_flags);
+#endif
+}
+
+ctintr(unit)
+       register int unit;
+{
+       register struct ct_softc *sc = &ct_softc[unit];
+       register struct buf *bp;
+       u_char stat;
+
+       bp = cttab[unit].b_actf;
+       if (bp == NULL) {
+               printf("ct%d: bp == NULL\n", unit);
+               return;
+       }
+       if (sc->sc_flags & CTF_IO) {
+               sc->sc_flags &= ~CTF_IO;
+               if (hpibustart(sc->sc_hd->hp_ctlr))
+                       ctgo(unit);
+               return;
+       }
+       if ((sc->sc_flags & CTF_STATWAIT) == 0) {
+               if (hpibpptest(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave) == 0) {
+                       sc->sc_flags |= CTF_STATWAIT;
+                       hpibawait(sc->sc_hd->hp_ctlr);
+                       return;
+               }
+       } else
+               sc->sc_flags &= ~CTF_STATWAIT;
+       hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_QSTAT, &stat, 1);
+#ifdef DEBUG
+       if (ctdebug & CDB_FILES)
+               printf("ctintr: before flags %x\n", sc->sc_flags);
+#endif
+       if (stat) {
+               sc->sc_rsc.unit = C_SUNIT(sc->sc_punit);
+               sc->sc_rsc.cmd = C_STATUS;
+               hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_CMD,
+                       &sc->sc_rsc, sizeof(sc->sc_rsc));
+               hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_EXEC,
+                       &sc->sc_stat, sizeof(sc->sc_stat));
+               hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_QSTAT,
+                       &stat, 1);
+#ifdef DEBUG
+               if (ctdebug & CDB_FILES)
+                       printf("ctintr: return stat 0x%x, A%x F%x blk %d\n",
+                              stat, sc->sc_stat.c_aef,
+                              sc->sc_stat.c_fef, sc->sc_stat.c_blk);
+#endif
+               if (stat == 0) {
+                       if (sc->sc_stat.c_aef & (AEF_EOF | AEF_EOV)) {
+                               cteof(sc, bp);
+                               ctaddeof(unit);
+                               goto done;
+                       }
+                       if (sc->sc_stat.c_fef & FEF_PF) {
+                               ctreset(sc, sc->sc_hd);
+                               ctstart(unit);
+                               return;
+                       }
+                       if (sc->sc_stat.c_fef & FEF_REXMT) {
+                               ctstart(unit);
+                               return;
+                       }
+                       if (sc->sc_stat.c_aef & 0x5800) {
+                               if (sc->sc_stat.c_aef & 0x4000)
+                                       tprintf(sc->sc_ctty,
+                                               "ct%d: uninitialized media\n",
+                                               unit);
+                               if (sc->sc_stat.c_aef & 0x1000)
+                                       tprintf(sc->sc_ctty,
+                                               "ct%d: not ready\n", unit);
+                               if (sc->sc_stat.c_aef & 0x0800)
+                                       tprintf(sc->sc_ctty,
+                                               "ct%d: write protect\n", unit);
+                       } else {
+                               printf("ct%d err: v%d u%d ru%d bn%d, ",
+                                      unit,
+                                      (sc->sc_stat.c_vu>>4)&0xF,
+                                      sc->sc_stat.c_vu&0xF,
+                                      sc->sc_stat.c_pend,
+                                      sc->sc_stat.c_blk);
+                               printf("R0x%x F0x%x A0x%x I0x%x\n",
+                                      sc->sc_stat.c_ref,
+                                      sc->sc_stat.c_fef,
+                                      sc->sc_stat.c_aef,
+                                      sc->sc_stat.c_ief);
+                       }
+               } else
+                       printf("ct%d: request status failed\n", unit);
+               bp->b_flags |= B_ERROR;
+               bp->b_error = EIO;
+               goto done;
+       } else
+               bp->b_resid = 0;
+       if (sc->sc_flags & CTF_CMD) {
+               switch (sc->sc_cmd) {
+               case MTFSF:
+                       sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF);
+                       sc->sc_blkno += CTBTOK(sc->sc_resid);
+                       ctstart(unit);
+                       return;
+               case MTBSF:
+                       sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF|CTF_EOT);
+                       break;
+               case MTBSR:
+                       sc->sc_flags &= ~CTF_BEOF;
+                       if (sc->sc_flags & CTF_EOT) {
+                               sc->sc_flags |= CTF_AEOF;
+                               sc->sc_flags &= ~CTF_EOT;
+                       } else if (sc->sc_flags & CTF_AEOF) {
+                               sc->sc_flags |= CTF_BEOF;
+                               sc->sc_flags &= ~CTF_AEOF;
+                       }
+                       break;
+               case MTWEOF:
+                       sc->sc_flags &= ~CTF_BEOF;
+                       if (sc->sc_flags & (CTF_AEOF|CTF_EOT)) {
+                               sc->sc_flags |= CTF_EOT;
+                               sc->sc_flags &= ~CTF_AEOF;
+                       } else
+                               sc->sc_flags |= CTF_AEOF;
+                       break;
+               case MTREW:
+               case MTOFFL:
+                       sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF|CTF_EOT);
+                       break;
+               }
+       } else {
+               sc->sc_flags &= ~CTF_AEOF;
+               sc->sc_blkno += CTBTOK(sc->sc_resid);
+       }
+done:
+#ifdef DEBUG
+       if (ctdebug & CDB_FILES)
+               printf("ctintr: after flags %x\n", sc->sc_flags);
+#endif
+       cttab[unit].b_actf = bp->av_forw;
+       iodone(bp);
+       hpibfree(&sc->sc_dq);
+       if (cttab[unit].b_actf == NULL) {
+               cttab[unit].b_active = 0;
+               return;
+       }
+       ctustart(unit);
+}
+
+ctread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = UNIT(dev);
+
+       return(physio(ctstrategy, &ctbuf[unit], dev, B_READ, minphys, uio));
+}
+
+ctwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = UNIT(dev);
+
+       return(physio(ctstrategy, &ctbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+/*ARGSUSED*/
+ctioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct mtop *op;
+       register int cnt;
+
+       switch (cmd) {
+
+       case MTIOCTOP:
+               op = (struct mtop *)data;
+               switch(op->mt_op) {
+
+               case MTWEOF:
+               case MTFSF:
+               case MTBSR:
+               case MTBSF:
+               case MTFSR:
+                       cnt = op->mt_count;
+                       break;
+
+               case MTREW:
+               case MTOFFL:
+                       cnt = 1;
+                       break;
+
+               default:
+                       return(EINVAL);
+               }
+               ctcommand(dev, op->mt_op, cnt);
+               break;
+
+       case MTIOCGET:
+               break;
+
+       default:
+               return(EINVAL);
+       }
+       return(0);
+}
+
+/*ARGSUSED*/
+ctdump(dev)
+       dev_t dev;
+{
+       return(ENXIO);
+}
+
+ctaddeof(unit)
+       int unit;
+{
+       register struct ct_softc *sc = &ct_softc[unit];
+       
+       if (sc->sc_eofp == EOFS - 1)
+               sc->sc_eofs[EOFS - 1]++;
+       else {
+               sc->sc_eofp++;
+               if (sc->sc_eofp == EOFS - 1)
+                       sc->sc_eofs[EOFS - 1] = EOFS;
+               else
+                       /* save blkno */
+                       sc->sc_eofs[sc->sc_eofp] = sc->sc_blkno - 1;
+       }
+#ifdef DEBUG
+       if (ctdebug & CT_BSF)
+               printf("ct%d: add eof pos %d blk %d\n",
+                      unit, sc->sc_eofp,
+                      sc->sc_eofs[sc->sc_eofp]);
+#endif
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/ctreg.h b/usr/src/sys/hp300/dev/ctreg.h
new file mode 100644 (file)
index 0000000..f7a42ea
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ctreg.h     7.1 (Berkeley) %G%
+ */
+
+struct ct_iocmd {
+       char    unit;
+       char    saddr;
+       short   addr0;
+       long    addr;
+       char    nop2;
+       char    slen;
+       long    len;
+       char    nop3;
+       char    cmd;
+};
+
+struct ct_rscmd {
+       char    unit;
+       char    cmd;
+};
+
+struct ct_stat {
+       char    c_vu;
+       char    c_pend;
+       short   c_ref;
+       short   c_fef;
+       short   c_aef;
+       short   c_ief;
+       short   c_blk0;
+       long    c_blk;
+       char    c_pad[4];
+};
+
+struct ct_ssmcmd {
+       char    unit;
+       char    cmd;
+       short   refm;
+       short   fefm;
+       short   aefm;
+       short   iefm;
+};
+
+struct ct_srcmd {
+       char    unit;
+       char    nop;
+       char    cmd;
+       char    param;
+};
+
+struct ct_soptcmd {
+       char    unit;
+       char    nop;
+       char    cmd;
+       char    opt;
+};
+
+struct ct_ulcmd {
+       char    unit;
+       char    cmd;
+};
+
+struct ct_wfmcmd {
+       char    unit;
+       char    cmd;
+};
+
+struct ct_clearcmd {
+       char    unit;
+       char    cmd;
+};
+
+struct ct_describe {
+       u_int   d_iuw:16,       /* controller: installed unit word */
+               d_cmaxxfr:16,   /* controller: max transfer rate (Kb) */
+               d_ctype:8,      /* controller: controller type */
+               d_utype:8,      /* unit: unit type */
+               d_name:24,      /* unit: name (6 BCD digits) */
+               d_sectsize:16,  /* unit: # of bytes per block (sector) */
+               d_blkbuf:8,     /* unit: # of blocks which can be buffered */
+               d_burstsize:8,  /* unit: recommended burst size */
+               d_blocktime:16, /* unit: block time (u-sec) */
+               d_uavexfr:16,   /* unit: average transfer rate (Kb) */
+               d_retry:16,     /* unit: optimal retry time (1/100-sec) */
+               d_access:16,    /* unit: access time param (1/100-sec) */
+               d_maxint:8,     /* unit: maximum interleave */
+               d_fvbyte:8,     /* unit: fixed volume byte */
+               d_rvbyte:8,     /* unit: removeable volume byte */
+               d_maxcyl:24,    /* volume: maximum cylinder */
+               d_maxhead:8,    /* volume: maximum head */
+               d_maxsect:16,   /* volume: maximum sector on track */
+               d_maxvsecth:16, /* volume: maximum sector on volume (MSW) */
+               d_maxvsectl:32, /* volume: maximum sector on volume (LSWs) */
+               d_interleave:8; /* volume: current interleave */
+ };
+
+#define        CT7946ID        0x220
+#define CT9145ID       0x268
+#define        CT9144ID        0x260
+#define        CT9144          0
+#define        CT7912PID       0x209
+#define        CT7914PID       0x20B
+#define        CT88140         1
+
+/* convert bytes to 1k tape block and back */
+#define CTBTOK(x)      ((x) >> 10)
+#define CTKTOB(x)      ((x) << 10)
+
+#define        CTCTLR          15
+
+#define        REF_MASK        0x0
+#define        FEF_MASK        0x0
+#define        AEF_MASK        0x0
+#define        IEF_MASK        0xF970
+
+#define        FEF_PF          0x0002
+#define        FEF_REXMT       0x0001
+#define        AEF_EOF         0x0010
+#define        AEF_EOV         0x0008
+
+#define        C_READ          0x00
+#define        C_WRITE         0x02
+#define        C_CLEAR         0x08
+#define        C_STATUS        0x0d
+#define        C_SADDR         0x10
+#define        C_SLEN          0x18
+#define        C_SUNIT(x)      (0x20 | (x))
+#define        C_SVOL(x)       (0x40 | (x))
+#define        C_NOP           0x34
+#define C_DESC         0x35
+#define        C_SOPT          0x38
+#define        C_SREL          0x3b
+#define        C_SSM           0x3e
+#define        C_WFM           0x49
+#define        C_UNLOAD        0x4a
+#define        C_REL           0x140
+
+#define        C_CMD           0x05
+#define        C_EXEC          0x0e
+#define        C_QSTAT         0x10
+#define        C_TCMD          0x12
+
+#define C_CC            1
+#define C_SKSPAR        2
+#define        C_OPT           4
+#define C_SPAR          4
+#define C_IMRPT         8
diff --git a/usr/src/sys/hp300/dev/dcm.c b/usr/src/sys/hp300/dev/dcm.c
new file mode 100644 (file)
index 0000000..7952866
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: $Hdr: dcm.c 1.17 89/10/01$
+ *
+ *     @(#)dcm.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ *  Console support is not finished.
+ */
+
+#include "dcm.h"
+#if NDCM > 0
+/*
+ *  98642/MUX
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+#include "time.h"
+
+#include "device.h"
+#include "dcmreg.h"
+#include "machine/cpu.h"
+#include "machine/isr.h"
+
+int    dcmprobe();
+struct driver dcmdriver = {
+       dcmprobe, "dcm",
+};
+
+#define NDCMLINE (NDCM*4)
+
+int    dcmstart(), dcmparam(), dcmintr();
+int    dcmsoftCAR[NDCM];
+int     dcmintschm[NDCM];
+int    dcm_active;
+int    ndcm = NDCM;
+int    dcmconsole = -1;
+struct dcmdevice *dcm_addr[NDCM];
+struct tty dcm_tty[NDCMLINE];
+int    dcm_cnt = NDCMLINE;
+struct isr dcmisr[NDCM];
+int     dcmintrval = 5; /* rate in secs that interschem is examined */
+long    dcmbang[NDCM];
+int    dcmchrrd[NDCM]; /* chars read during each sample time */
+int     dcmintrocc[NDCM];      /* # of interrupts for each sample time */
+
+
+struct speedtab dcmspeedtab[] = {
+       0,      BR_0,
+       50,     BR_50,
+       75,     BR_75,
+       110,    BR_110,
+       134,    BR_134,
+       150,    BR_150,
+       300,    BR_300,
+       600,    BR_600,
+       1200,   BR_1200,
+       1800,   BR_1800,
+       2400,   BR_2400,
+       4800,   BR_4800,
+       9600,   BR_9600,
+       19200,  BR_19200,
+       38400,  BR_38400,
+       -1,     -1
+};
+
+#ifdef DEBUG
+int    dcmdebug = 0x00;
+#define DDB_SIOERR     0x01
+#define DDB_PARAM      0x02
+#define DDB_INPUT      0x04
+#define DDB_OUTPUT     0x08
+#define DDB_INTR       0x10
+#define DDB_IOCTL       0x20
+#define DDB_INTSCHM     0x40
+#define DDB_MOD         0x80
+#define DDB_OPENCLOSE  0x100
+
+long unsigned int dcmrsize[33];        /* read sizes, 32 for over 31, 0 for 0 */
+#endif
+
+extern struct tty *constty;
+
+#define UNIT(x)                minor(x)
+#define        BOARD(x)        ((x) >> 2)
+#define PORT(x)                ((x) & 3)
+#define MKUNIT(b,p)    (((b) << 2) | (p))
+
+dcmprobe(hd)
+       register struct hp_device *hd;
+{
+       register struct dcmdevice *dcm;
+       register int i;
+       register int timo = 0;
+       int s, brd;
+
+       dcm = (struct dcmdevice *)hd->hp_addr;
+       if ((dcm->dcm_rsid & 0x1f) != DCMID)
+               return (0);
+       brd = hd->hp_unit;
+       s = spltty();
+       dcm->dcm_rsid = DCMRS;
+       DELAY(50000);   /* 5000 is not long enough */
+       dcm->dcm_rsid = 0; 
+       dcm->dcm_ic = IC_IE;
+       dcm->dcm_cr = CR_SELFT;
+       while ((dcm->dcm_ic & IC_IR) == 0) {
+               if (++timo == 20000) {
+                       printf("dcm%d: timeout on selftest interrupt\n", brd);
+                       printf("dcm%d:rsid %x, ic %x, cr %x, iir %x\n",
+                              brd, dcm->dcm_rsid, dcm->dcm_ic,
+                              dcm->dcm_cr, dcm->dcm_iir);
+                       return(0);
+               }
+       }
+       DELAY(50000)    /* XXX why is this needed ???? */
+       while ((dcm->dcm_iir & IIR_SELFT) == 0) {
+               if (++timo == 400000) {
+                       printf("dcm%d: timeout on selftest\n", brd);
+                       printf("dcm%d:rsid %x, ic %x, cr %x, iir %x\n",
+                              brd, dcm->dcm_rsid, dcm->dcm_ic,
+                              dcm->dcm_cr, dcm->dcm_iir);
+                       return(0);
+               }
+       }
+       DELAY(50000)    /* XXX why is this needed ???? */
+       if (dcm->dcm_stcon != ST_OK) {
+               printf("dcm%d: self test failed: %x\n", brd, dcm->dcm_stcon);
+               return(0);
+       }
+       dcm->dcm_ic = IC_ID;
+       splx(s);
+
+       hd->hp_ipl = DCMIPL(dcm->dcm_ic);
+       dcmisr[brd].isr_ipl = hd->hp_ipl;
+       dcmisr[brd].isr_arg = brd;
+       dcmisr[brd].isr_intr = dcmintr;
+       dcm_addr[brd] = dcm;
+       dcm_active |= 1 << brd;
+       dcmsoftCAR[brd] = hd->hp_flags;
+       dcmintschm[brd] = 1;    /* start with interrupt/char */
+       for (i = 0; i < 256; i++)
+               dcm->dcm_bmap[i].data_data = 0x0f;
+       dcmintrocc[brd] = 0;
+       dcmchrrd[brd] = 0;
+       isrlink(&dcmisr[brd]);
+       dcm->dcm_mdmmsk = MI_CD;        /* Enable carrier detect interrupts */
+       dcm->dcm_ic = IC_IE;    /* turn interrupts on */
+       /*
+        * Need to reset baud rate, etc. of next print so reset dcmconsole.
+        * Also make sure console is always "hardwired"
+        */
+       if (brd == BOARD(dcmconsole)) {
+               dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
+               dcmconsole = -1;
+       }
+       return (1);
+}
+
+dcmopen(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register int unit, brd;
+
+       unit = UNIT(dev);
+       brd = BOARD(unit);
+       dcmbang[brd] = time.tv_sec;     /* for interrupt scheme */
+       if (unit >= dcm_cnt || (dcm_active & (1 << brd)) == 0)
+               return (ENXIO);
+       tp = &dcm_tty[unit];
+       tp->t_oproc = dcmstart;
+       tp->t_param = dcaparam;
+       tp->t_dev = dev;
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+               dcmparam(tp, &tp->t_termios);
+               ttsetwater(tp);
+       } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+               return (EBUSY);
+       if (PORT(unit) == 0)    /* enable port 0 */
+               (void) dcmmctl(dev, MO_ON, DMSET);
+       if (dcmsoftCAR[brd] & (1 << PORT(unit)))
+               tp->t_state |= TS_CARR_ON;
+       else if (PORT(unit))            /* Only port 0 has modem control */
+               tp->t_state |= TS_CARR_ON;
+       else if (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)
+               tp->t_state |= TS_CARR_ON;
+       (void) spltty();
+       while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
+              (tp->t_state & TS_CARR_ON) == 0) {
+               tp->t_state |= TS_WOPEN;
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       }
+       (void) spl0();
+
+#ifdef DEBUG
+       if (dcmdebug & DDB_OPENCLOSE)
+               printf("dcmopen: u %x st %x fl %x\n",
+                       unit, tp->t_state, tp->t_flags);
+#endif
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+/*ARGSUSED*/
+dcmclose(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       int unit;
+       unit = UNIT(dev);
+       tp = &dcm_tty[unit];
+       (*linesw[tp->t_line].l_close)(tp);
+       if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 
+           (tp->t_state&TS_ISOPEN) == 0)
+               (void) dcmmctl(dev, MO_OFF, DMSET);
+#ifdef DEBUG
+       if (dcmdebug & DDB_OPENCLOSE)
+               printf("dcmclose: u %x st %x fl %x\n",
+                       unit, tp->t_state, tp->t_flags);
+#endif
+       ttyclose(tp);
+       return(0);
+}
+dcmread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp;
+       tp = &dcm_tty[UNIT(dev)];
+       return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+dcmwrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       int unit = UNIT(dev);
+       register struct tty *tp;
+       tp = &dcm_tty[unit];
+       if (unit == dcmconsole && constty &&
+           (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN))
+               tp = constty;
+       return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+dcmintr(brd)
+       register int brd;
+{
+       register struct dcmdevice *dcm;
+       int i, code, pcnd[4], mcnd, delta;
+
+       dcm = dcm_addr[brd];
+       SEM_LOCK(dcm);
+       if ((dcm->dcm_ic & IC_IR) == 0) {
+               SEM_UNLOCK(dcm);
+               return(0);
+       }
+       for (i = 0; i < 4; i++) {
+               pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
+               dcm->dcm_icrtab[i].dcm_data = 0;
+       }
+       mcnd = dcm->dcm_mdmin;
+       code = dcm->dcm_iir & IIR_MASK;
+       dcm->dcm_iir = 0;
+       SEM_UNLOCK(dcm);
+
+#ifdef DEBUG
+       if (dcmdebug & DDB_INTR)
+               printf("dcmintr: iir %x p0 %x p1 %x p2 %x p3 %x m %x\n", 
+                       code, pcnd[0], pcnd[1], pcnd[2], 
+                       pcnd[3], mcnd);
+#endif
+       if (code & IIR_PORT0)
+               dcmpint(MKUNIT(brd, 0), pcnd[0], dcm);
+       if (code & IIR_PORT1)
+               dcmpint(MKUNIT(brd, 1), pcnd[1],  dcm);
+       if (code & IIR_PORT2)
+               dcmpint(MKUNIT(brd, 2), pcnd[2], dcm);
+       if (code & IIR_PORT3)
+               dcmpint(MKUNIT(brd, 3), pcnd[3], dcm);
+       if (code & IIR_MODM)
+               dcmmint(MKUNIT(brd, 0), mcnd, dcm);     /* always port 0 */
+       if (code & IIR_TIMEO)
+               dcmrint(brd, dcm);
+
+       /*
+        * See if need to change interrupt rate.
+        * 16.7ms is the polling interrupt rate.
+        * Reference: 16.7ms is about 550 buad; 38.4k is 72 chars in 16.7ms
+        */
+       if ((delta = time.tv_sec - dcmbang[brd]) >= dcmintrval) {  
+               dcmbang[brd] = time.tv_sec;
+               /*
+                * 66 threshold of 600 buad, use 70
+                */
+               if (dcmintschm[brd] && dcmintrocc[brd] > 70 * delta)
+                       dcm_setintrschm(dcm, 0, brd);
+               else if (!dcmintschm[brd] && dcmintrocc[brd] > dcmchrrd[brd]) {
+                       dcm_setintrschm(dcm, 1, brd);
+                       /*
+                        * Must check the receive queue after switch
+                        * from polling mode to interrupt/char
+                        */
+                       dcmrint(brd, dcm);
+               }
+               dcmintrocc[brd] = 0;
+               dcmchrrd[brd] = 0;
+       } else
+               dcmintrocc[brd]++;
+
+       return(1);
+}
+
+/*
+ *  Port interrupt.  Can be two things:
+ *     First, it might be a special character (exception interrupt);
+ *     Second, it may be a buffer empty (transmit interrupt);
+ */
+dcmpint(unit, code, dcm)
+       int unit, code;
+       register struct dcmdevice *dcm;
+{
+       register struct tty *tp;
+       register int port = PORT(unit);
+
+       if (code & IT_SPEC) {
+               tp = &dcm_tty[unit];
+               if ((tp->t_state & TS_ISOPEN) != 0)
+                       dcmreadbuf(unit, dcm, tp, port);
+               else
+                       dcm->dcm_rhead[port].ptr = dcm->dcm_rtail[port].ptr & RX_MASK;
+       }
+       if (code & IT_TX)
+               dcmxint(unit, dcm);
+}
+
+dcmrint(brd, dcm)
+       int brd;
+       register struct dcmdevice *dcm;
+{
+       register struct tty *tp;
+       register int i, unit;
+
+       unit = MKUNIT(brd, 0);
+       tp = &dcm_tty[unit];
+       for (i = 0; i < 4; i++, tp++, unit++) {
+               /* TS_WOPEN catch race when switching to polling mode */
+               if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) != 0)
+                       dcmreadbuf(unit, dcm, tp, i);
+               else
+                       dcm->dcm_rhead[i].ptr = dcm->dcm_rtail[i].ptr & RX_MASK;
+       }
+}
+
+dcmreadbuf(unit, dcm, tp, port)
+       int unit;
+       register struct dcmdevice *dcm;
+       register struct tty *tp;
+       register int port;
+{
+       register int c, stat;
+       register unsigned head;
+       unsigned tail;
+#ifdef DEBUG
+       int silocnt;
+       silocnt = 0;
+#endif /* DEBUG */
+
+readrestart:
+       head = dcm->dcm_rhead[port].ptr & RX_MASK;
+       tail = dcm->dcm_rtail[port].ptr & RX_MASK;
+
+       while (head != tail) {
+               c = dcm->dcm_rfifos[3 - port][head / 2].data_char;
+               stat = dcm->dcm_rfifos[3 - port][head / 2].data_stat;
+               dcmchrrd[BOARD(unit)]++;
+#ifdef DEBUG
+               silocnt++;
+#endif
+               head = (head + 2) & RX_MASK;
+               dcm->dcm_rhead[port].ptr = head;
+
+#ifdef DEBUG
+               if (dcmdebug & DDB_INPUT)
+                       printf("dcmreadbuf: u%d p%d c%x s%x f%x h%x t%x char %c\n",
+                              BOARD(unit), PORT(unit), c&0xFF, stat&0xFF,
+                              tp->t_flags, head, tail, c);
+#endif
+               if (stat & RD_MASK) {   /* Check for errors */
+#ifdef DEBUG
+                       if (dcmdebug & DDB_INPUT || dcmdebug & DDB_SIOERR)
+                               printf("dcm%d port%d: data error: stat 0x%x data 0x%x chr %c\n",
+                                      BOARD(unit), PORT(unit), stat, c, c);
+#endif
+                       if (stat & (RD_BD | RD_FE))
+                               c |= TTY_FE;
+                       else if (stat & RD_PE)
+                               c |= TTY_PE;
+                       else if (stat & RD_OVF)
+                               log(LOG_WARNING,
+                                   "dcm%d port%d: silo overflow\n",
+                                   BOARD(unit), PORT(unit));
+                       else if (stat & RD_OE)
+                               log(LOG_WARNING,
+                                   "dcm%d port%d: uart overflow\n",
+                                   BOARD(unit), PORT(unit));
+               }
+               (*linesw[tp->t_line].l_rint)(c, tp);
+       }
+       /* for higher speed need to processes everything that might
+        * have arrived since we started; see if tail changed */
+       if (tail != dcm->dcm_rtail[port].ptr & RX_MASK)
+               goto readrestart;
+
+#ifdef DEBUG
+       if (silocnt < 33)
+               dcmrsize[silocnt]++;
+       else
+               dcmrsize[32]++;
+#endif
+}
+
+dcmxint(unit, dcm)
+       int unit;
+       struct dcmdevice *dcm;
+{
+       register struct tty *tp;
+
+       tp = &dcm_tty[unit];
+       tp->t_state &= ~TS_BUSY;
+       if (tp->t_state & TS_FLUSH)
+               tp->t_state &= ~TS_FLUSH;
+       if (tp->t_line)
+               (*linesw[tp->t_line].l_start)(tp);
+       else
+               dcmstart(tp);
+}
+
+dcmmint(unit, mcnd, dcm)
+       register int unit;
+       register struct dcmdevice *dcm;
+        int mcnd;
+{
+       register struct tty *tp;
+
+#ifdef DEBUG
+       if (dcmdebug & DDB_MOD)
+               printf("dcmmint: unit %x mcnd %x\n", unit, mcnd);
+#endif DEBUG
+       tp = &dcm_tty[unit];
+       if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) {
+               if (mcnd & MI_CD)
+                       (void) (*linesw[tp->t_line].l_modem)(tp, 1);
+               else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
+                       dcm->dcm_mdmout &= ~(MO_DTR | MO_RTS);
+                       SEM_LOCK(dcm);
+                       dcm->dcm_cr |= CR_MODM;
+                       SEM_UNLOCK(dcm);
+               }
+       }
+}
+
+dcmioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct tty *tp;
+       register int unit = UNIT(dev);
+       register struct dcmdevice *dcm;
+       register int port;
+       int error;
+#ifdef DEBUG
+       if (dcmdebug & DDB_IOCTL)
+               printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
+                      unit, cmd, *data, flag);
+#endif
+       tp = &dcm_tty[unit];
+       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+       if (error >= 0)
+               return (error);
+       error = ttioctl(tp, cmd, data, flag);
+       if (error >= 0)
+               return (error);
+
+       port = PORT(unit);
+       dcm = dcm_addr[BOARD(unit)];
+       switch (cmd) {
+       case TIOCSBRK:
+               dcm->dcm_cmdtab[port].dcm_data = CT_BRK;
+               SEM_LOCK(dcm);
+               dcm->dcm_cr = (1 << port);      /* start break */
+               SEM_UNLOCK(dcm);
+               break;
+
+       case TIOCCBRK:
+               dcm->dcm_cmdtab[port].dcm_data = CT_BRK;
+               SEM_LOCK(dcm);
+               dcm->dcm_cr = (1 << port);      /* end break */
+               SEM_UNLOCK(dcm);
+               break;
+
+       case TIOCSDTR:
+               (void) dcmmctl(dev, MO_ON, DMBIS);
+               break;
+
+       case TIOCCDTR:
+               (void) dcmmctl(dev, MO_ON, DMBIC);
+               break;
+
+       case TIOCMSET:
+               (void) dcmmctl(dev, *(int *)data, DMSET);
+               break;
+
+       case TIOCMBIS:
+               (void) dcmmctl(dev, *(int *)data, DMBIS);
+               break;
+
+       case TIOCMBIC:
+               (void) dcmmctl(dev, *(int *)data, DMBIC);
+               break;
+
+       case TIOCMGET:
+               *(int *)data = dcmmctl(dev, 0, DMGET);
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+dcmparam(tp, t)
+       register struct tty *tp;
+       register struct termios *t;
+{
+       register struct dcmdevice *dcm;
+       register int mode, cflag = t->c_cflag;
+       register int port;
+       int unit = UNIT(tp->t_dev);
+       int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
+       /* check requested parameters */
+        if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+                return(EINVAL);
+        /* and copy to tty */
+        tp->t_ispeed = t->c_ispeed;
+        tp->t_ospeed = t->c_ospeed;
+        tp->t_cflag = cflag;
+
+       dcm = dcm_addr[BOARD(unit)];
+       if (ospeed == 0) {
+               (void) dcmmctl(unit, MO_OFF, DMSET);    /* hang up line */
+               return;
+       }
+       port = PORT(unit);
+       dcm->dcm_data[port].dcm_baud = ospeed;
+       switch (cflag&CSIZE) {
+       case CS5:
+               mode = LC_5BITS; break;
+       case CS6:
+               mode = LC_6BITS; break;
+       case CS7:
+               mode = LC_7BITS; break;
+       case CS8:
+               mode = LC_8BITS; break;
+       }
+       if (cflag&PARENB) {
+               if (cflag&PARODD)
+                       mode |= LC_PODD;
+               else
+                       mode |= LC_PEVEN;
+       }
+       if (cflag&CSTOPB)
+               mode |= LC_2STOP;
+       else
+               mode |= LC_1STOP;
+#ifdef DEBUG
+       if (dcmdebug & DDB_PARAM)
+               printf("dcmparam: unit %d cflag %x mode %x speed %x\n",
+                      unit, cflag, mode, ospeed);
+#endif
+       /* wait for transmitter buffer to empty */
+       while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
+               ;
+
+       dcm->dcm_data[port].dcm_conf = mode;
+       dcm->dcm_cmdtab[port].dcm_data = CT_CON;
+       SEM_LOCK(dcm);
+       dcm->dcm_cr = (1 << port);
+       SEM_UNLOCK(dcm);
+}
+dcmstart(tp)
+       register struct tty *tp;
+{
+       register struct dcmdevice *dcm;
+       int s, unit, c;
+       register int tail, next, head, port;
+       int restart = 0, nch = 0;
+       unit = UNIT(tp->t_dev);
+       port = PORT(unit);
+       dcm = dcm_addr[BOARD(unit)];
+       s = spltty();
+#ifdef DEBUG
+       if (dcmdebug & DDB_OUTPUT)
+               printf("dcmstart: unit %d state %x flags %x outcc %d\n",
+                      unit, tp->t_state, tp->t_flags, tp->t_outq.c_cc);
+#endif
+       if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+               goto out;
+       if (tp->t_outq.c_cc <= tp->t_lowat) {
+               if (tp->t_state&TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup((caddr_t)&tp->t_outq);
+               }
+               if (tp->t_wsel) {
+                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+                       tp->t_wsel = 0;
+                       tp->t_state &= ~TS_WCOLL;
+               }
+       }
+       tail = dcm->dcm_ttail[port].ptr & TX_MASK;
+       next = (dcm->dcm_ttail[port].ptr + 1) & TX_MASK;
+       head = dcm->dcm_thead[port].ptr & TX_MASK;
+#ifdef DEBUG
+      if (dcmdebug & DDB_OUTPUT)
+              printf("\thead %x tail %x next %x\n",
+                     head, tail, next);
+#endif
+       if (tail == head && tp->t_outq.c_cc)
+               restart++;
+       while (tp->t_outq.c_cc && next != head) {
+               nch++;
+               c = getc(&tp->t_outq);
+               dcm->dcm_tfifos[3 - port][tail].data_char = c;
+               dcm->dcm_ttail[port].ptr = next;
+               tail = next;
+               next = (tail + 1) & TX_MASK;
+       }
+       if (restart && nch) {
+               tp->t_state |= TS_BUSY;
+               SEM_LOCK(dcm);
+#ifdef DEBUG
+       if (dcmdebug & DDB_INTR)
+               printf("TX on port %d head %x tail %x cc %d\n",
+                       port, tail, head, tp->t_outq.c_cc);
+#endif
+               dcm->dcm_cmdtab[port].dcm_data = CT_TX;
+               dcm->dcm_cr = (1 << port);
+               SEM_UNLOCK(dcm);
+       }
+out:
+       splx(s);
+}
+/*
+ * Stop output on a line.
+ */
+dcmstop(tp, flag)
+       register struct tty *tp;
+{
+       int s;
+
+       s = spltty();
+       if (tp->t_state & TS_BUSY) {
+               if ((tp->t_state&TS_TTSTOP)==0)
+                       tp->t_state |= TS_FLUSH;
+       }
+       splx(s);
+}
+/* Modem control */
+
+dcmmctl(dev, bits, how)
+       dev_t dev;
+       int bits, how;
+{
+       register struct dcmdevice *dcm;
+       int s, hit = 0;
+
+       /* Only port 0 has modem control lines. For right now the following */
+       /* is ok, but needs to changed for the 8 port board. */
+       if (PORT(UNIT(dev)) != 0)
+               return(bits);
+
+       dcm = dcm_addr[BOARD(UNIT(dev))];
+       s = spltty();
+       switch (how) {
+
+       case DMSET:
+               dcm->dcm_mdmout = bits;
+               hit++;
+               break;
+
+       case DMBIS:
+               dcm->dcm_mdmout |= bits;
+               hit++;
+               break;
+
+       case DMBIC:
+               dcm->dcm_mdmout &= ~bits;
+               hit++;
+               break;
+
+       case DMGET:
+               bits = dcm->dcm_mdmin;
+               break;
+       }
+       if (hit) {
+               SEM_LOCK(dcm);
+               dcm->dcm_cr |= CR_MODM;
+               SEM_UNLOCK(dcm);
+               (void) splx(s);
+       }
+       return(bits);
+}
+
+dcm_setintrschm(dcm, request, brd)
+     register struct dcmdevice *dcm;
+     int request, brd;
+{
+       register int i;
+
+#ifdef DEBUG
+       if (dcmdebug & DDB_INTSCHM) {
+               printf("dcm%d set intr schm request %d int state %x silo hist \n\t",
+                      brd, request, dcmintschm[brd]);
+               for (i = 0; i < 33; i++)  {
+                       printf("  %u", dcmrsize[i]);
+                       dcmrsize[i] = 0;
+               }
+               printf("\n");
+       }
+#endif /* DEBUG */
+
+       /* if request true then we interrupt per char, else use card */
+       /* polling interrupt hardware */
+#ifdef DEBUG
+       if (request == dcmintschm[brd]) { 
+               printf("dcm%d setintrschm redundent request %x current %x\n",
+                      brd, request, dcmintschm[brd]);
+               return;
+       }
+#endif /* DEBUG */
+       if (request) {
+               for (i = 0; i < 256; i++)
+                       dcm->dcm_bmap[i].data_data = 0x0f;
+               dcmintschm[brd] = 1;
+       }
+       else {
+               for (i = 0; i < 256; i++) 
+                       dcm->dcm_bmap[i].data_data = 0x00;
+               /*
+                * Don't slow down tandem mode, interrupt on these chars.
+                * XXX bad assumption, everyone uses ^Q, ^S for flow
+                */
+               dcm->dcm_bmap[0x11].data_data = 0x0f;
+               dcm->dcm_bmap[0x13].data_data = 0x0f;
+               dcmintschm[brd] = 0;
+       }
+       while (dcm->dcm_cr & CR_TIMER) ;
+       SEM_LOCK(dcm);
+       dcm->dcm_cr |= CR_TIMER;        /* toggle card 16.7ms interrupts */
+       SEM_UNLOCK(dcm);
+}
+
+#ifdef notdef
+/*
+ * Following are all routines needed for DCM to act as console
+ */
+
+struct tty *
+dcmcninit(majordev)
+       dev_t majordev;
+{
+       register struct dcmdevice *dcm;
+       int unit, s;
+       short stat;
+
+       unit = CONUNIT;                         /* XXX */
+       dcm_addr[BOARD(CONUNIT)] = CONADDR;     /* XXX */
+
+       dcm = dcm_addr[unit];
+       s = splhigh();
+       /* do something */
+       splx(s);
+       dcmconsole = unit;
+       if (majordev)
+               dcm_tty[unit].t_dev = makedev(majordev, unit);
+       return(&dcm_tty[unit]);
+}
+
+dcmcngetc(dev)
+{
+       return(0);
+}
+
+/*
+ * Console kernel output character routine.
+ */
+dcmcnputc(dev, c)
+       dev_t dev;
+       register int c;
+{
+       register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
+       int port = PORT(dev);
+       short stat;
+       int head, tail, next;
+       int s = splhigh();
+
+       if (dcmconsole == -1)
+               (void) dcmcninit(0);
+
+       do {
+               tail = dcm->dcm_ttail[port].ptr & TX_MASK;
+               head = dcm->dcm_thead[port].ptr & TX_MASK;
+       } while (tail != head);
+       next = (dcm->dcm_ttail[port].ptr + 1) & TX_MASK;
+
+       dcm->dcm_tfifos[3 - port][tail].data_char = c;
+       dcm->dcm_ttail[port].ptr = next;
+
+       dcm->dcm_cmdtab[port].dcm_data = CT_TX;
+       SEM_LOCK(dcm);
+       dcm->dcm_cr = (1 << port);
+       SEM_UNLOCK(dcm);
+
+       splx(s);
+}
+#endif
+#endif
diff --git a/usr/src/sys/hp300/dev/dcmreg.h b/usr/src/sys/hp300/dev/dcmreg.h
new file mode 100644 (file)
index 0000000..8eb13d6
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: dcmreg.h 1.3 89/08/23$
+ *
+ *     @(#)dcmreg.h    7.1 (Berkeley) %G%
+ */
+
+struct dcmdevice {        /* host address, only odd bytes addressed */
+       u_char  dcm_pad0;
+       volatile u_char dcm_rsid;       /* Reset / ID                   0001 */
+       u_char  dcm_pad1;
+       volatile u_char dcm_ic;         /* Interrupt control register   0003 */
+       u_char  dcm_pad2;
+       volatile u_char dcm_sem;        /* Semaphore register           0005 */
+       u_char  dcm_pad3[0x7ffa];       /* Unaddressable   0006-7fff */
+       u_char  dcm_pad4;
+       volatile u_char dcm_iir;        /* Interrupt ident register     8001 */
+       u_char  dcm_pad5;
+       volatile u_char dcm_cr;         /* Command register             8003 */
+       u_char  dcm_pad6[0x3fc];        /* Card scratch    8004-83ff */
+       struct  {
+           u_char  ptr_pad1;
+           volatile u_char  data_char;
+           u_char  ptr_pad2;
+           volatile u_char  data_stat;
+       } dcm_rfifos[4][0x80];  /* Receive queues               8400 */
+       struct  {
+           u_char  ptr_pad1;
+           volatile u_char  data_data;
+       } dcm_bmap[0x100];      /* Bitmap table                 8c00 */
+       struct  {
+           u_char  ptr_pad;
+           volatile u_char  ptr;
+       } dcm_rhead[4];         /* Fifo head - receive          8e00 */
+       struct  {
+           u_char  ptr_pad;
+           volatile u_char  ptr;
+       } dcm_rtail[4];         /* Fifo tail - receive          8e08 */
+       struct  {
+           u_char  ptr_pad;
+           volatile u_char  ptr;
+       } dcm_thead[4];         /* Fifo head - transmit         8e10 */
+       struct  {
+           u_char  ptr_pad;
+           volatile u_char  ptr;
+       } dcm_ttail[4];         /* Fifo tail - transmit         8e18 */
+       struct  {
+               u_char pad1;
+               volatile u_char dcm_conf;
+               u_char pad2;
+               volatile u_char dcm_baud;
+       } dcm_data[4];          /* Configuration registers      8e20 */
+       u_char  dcm_pad7;
+       volatile u_char  dcm_mdmin;     /* Modem in                     8e31 */
+       u_char  dcm_pad8;
+       volatile u_char  dcm_mdmout;    /* Modem out                    8e33 */
+       u_char  dcm_pad9;
+       volatile u_char  dcm_mdmmsk;    /* Modem mask                   8e35 */
+       struct  {
+               u_char pad1;
+               volatile u_char dcm_data;
+       } dcm_cmdtab[4];        /* Command tables               8e36 */
+       struct  {
+               u_char pad1;
+               volatile u_char dcm_data;
+       } dcm_icrtab[4];        /* Interrupt data               8e3e */
+       u_char  dcm_pad10;
+       volatile u_char  dcm_stcon;     /* Self test condition          8e47 */
+       u_char  dcm_pad11[0x98];        /* Undef SR regs   8e48-8edf */
+       struct  {
+           u_char  ptr_pad1;
+           volatile u_char  data_char;
+       } dcm_tfifos[4][0x10];  /* Transmit queues              8ee0 */
+};
+
+/* interface reset/id */
+#define DCMCON          0x80   /* REMOTE/LOCAL switch, read */
+#define        DCMID           0x5     /* hardwired card id, read */
+#define        DCMRS           0x80    /* software reset, write */
+
+/* interrupt control */
+#define        DCMIPL(x)       ((((x) >> 4) & 3) + 3)  /* interupt level, read */
+#define        IC_IR           0x40    /* interupt request, read */
+#define        IC_IE           0x80    /* interupt enable, write */
+#define        IC_ID           0x00    /* interupt disable, write */
+
+
+/* Semaphore control */
+#define        SEM_BSY         0x80    /* read */
+#define SEM_CLR         0xFF   /* write */
+#define SEM_LOCK(dcm)  while ((dcm)->dcm_sem & SEM_BSY)
+#define SEM_UNLOCK(dcm)        (dcm)->dcm_sem = SEM_CLR
+
+/* command register */
+#define        CR_PORT0        0x1
+#define        CR_PORT1        0x2
+#define        CR_PORT2        0x4
+#define        CR_PORT3        0x8
+#define        CR_MODM         0x10    /* change modem output lines */
+#define        CR_TIMER        0x20    /* 16ms interrupt timer toggle */
+#define        CR_SELFT        0x40    /* run self test */
+#define CR_MASK                0x7f
+
+/* interrupt ident register */
+#define        IIR_PORT0       0x1
+#define        IIR_PORT1       0x2
+#define        IIR_PORT2       0x4
+#define        IIR_PORT3       0x8
+#define        IIR_SELFT       0x10    /* self test completed */
+#define        IIR_MODM        0x20    /* change in modem input lines */
+#define        IIR_TIMEO       0x40    /* Time out */
+#define IIR_MASK       0x7f
+
+/* self test cond reg */
+#define ST_OK           0xe0
+
+/* Line configuration register */
+#define        LC_PNO          0x00
+#define        LC_PODD         0x01
+#define        LC_PEVEN        0x02
+#define        LC_PMSK         0x03
+
+#define        LC_1STOP        0x00
+#define        LC_1HSTOP       0x04
+#define        LC_2STOP        0x08
+#define        LC_STOPMSK      0x0b
+
+#define        LC_8BITS        0x30
+#define        LC_7BITS        0x20
+#define        LC_6BITS        0x10
+#define        LC_5BITS        0x00
+#define        LC_BITMSK       0x30
+
+/* baud reg */
+#define BR_0           0x00
+#define BR_50          0x01
+#define BR_75          0x02
+#define BR_110         0x03
+#define BR_134         0x04
+#define BR_150         0x05
+#define BR_300         0x06
+#define BR_600         0x07
+#define BR_900         0x08
+#define BR_1200                0x09
+#define BR_1800                0x0a
+#define BR_2400                0x0b
+#define BR_3600                0x0c
+#define BR_4800                0x0d
+#define BR_7200                0x0e
+#define BR_9600                0x0f
+#define BR_19200       0x10
+#define BR_38400       0x11
+
+/* modem input register */
+#define        MI_CTS          0x08
+#define        MI_DM           0x04
+#define        MI_CD           0x02
+#define        MI_RI           0x01
+
+/* modem output register */
+#define        MO_SR           0x04
+#define        MO_DTR          0x02
+#define        MO_RTS          0x01
+#define        MO_ON           ((MO_DTR) | (MO_RTS))
+#define        MO_OFF          0x00
+
+/* cmd-tab values, write */
+#define CT_CON         0x1     /* configuration change */
+#define CT_TX          0x2     /* transmit buffer not empty */
+#define CT_BRK         0x4     /* toggle BREAK */
+
+/* icr-tab values, read */
+#define IT_TX          0x1     /* transmit buffer empty */
+#define IT_SPEC                0x2     /* special character received */
+
+/* data errors */
+#define RD_OVF         0x08
+#define RD_BD          0x10
+#define RD_PE          0x20
+#define RD_OE          0x40
+#define RD_FE          0x80
+#define RD_MASK                0xf8
+
+/* Transmit/Receive masks */
+#define TX_MASK                0x0f
+#define RX_MASK                0xff
+
+/*
+ * WARNING: Serial console is assumed to be at SC13
+ * and CONUNIT must be 1, signeled by REMOTE/LOCAL switch on card
+ */
+#define CONADDR        ((struct dcmdevice *)(IOV(EXTIOBASE + (13 * IOCARDSIZE))))
+#define CONUNIT        (1)
diff --git a/usr/src/sys/hp300/dev/dma.c b/usr/src/sys/hp300/dev/dma.c
new file mode 100644 (file)
index 0000000..3b4cb69
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)dma.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ * DMA driver
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "proc.h"
+#include "dmareg.h"
+#include "dmavar.h"
+#include "device.h"
+
+#include "machine/cpu.h"
+#include "machine/isr.h"
+
+extern void isrlink();
+extern void printf();
+extern void panic();
+extern void _insque();
+extern void _remque();
+extern void timeout();
+extern int splbio();
+extern void splx();
+extern u_int kvtop();
+extern void PCIA();
+
+/*
+ * The largest single request will be MAXPHYS bytes which will require
+ * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
+ * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
+ * buffer is not page aligned (+1).
+ */
+#define        DMAMAXIO        (MAXPHYS/NBPG+1)
+
+#define        DMATIMO         15
+
+struct dma_softc {
+       struct dmadevice *sc_hwaddr;
+       struct dmaBdevice *sc_Bhwaddr;
+       int     sc_type;
+       int     sc_cur;
+       int     sc_cmd;
+       int     sc_timo;
+       int     sc_count[DMAMAXIO+1];
+       char    *sc_addr[DMAMAXIO+1];
+} dma_softc[NDMA];
+
+/* types */
+#define        DMA_B   0
+#define DMA_C  1
+
+struct devqueue dmachan[NDMA + 1];
+int    dmaintr();
+void   dmatimo();
+
+#ifdef DEBUG
+int    dmadebug = 0;
+#define DDB_WORD       0x01    /* same as DMAGO_WORD */
+#define DDB_LWORD      0x02    /* same as DMAGO_LWORD */
+#define        DDB_FOLLOW      0x04
+#define DDB_IO         0x08
+
+long   dmahits[NDMA];
+long   dmamisses[NDMA];
+long   dmabyte[NDMA];
+long   dmaword[NDMA];
+long   dmalword[NDMA];
+#endif
+
+void
+dmainit()
+{
+       register struct dmareg *dma = (struct dmareg *)DMA_BASE;
+       register struct dma_softc *dc;
+       register int i;
+       char rev;
+
+       /*
+        * Determine the DMA type.
+        * Don't know how to easily differentiate the A and B cards,
+        * so we just hope nobody has an A card (A cards will work if
+        * DMAINTLVL is set to 3).
+        */
+       if (!badbaddr((char *)&dma->dma_id[2]))
+               rev = dma->dma_id[2];
+       else {
+               rev = 'B';
+#if !defined(HP320)
+               panic("dmainit: DMA card requires hp320 support");
+#endif
+       }
+
+       dc = &dma_softc[0];
+       for (i = 0; i < NDMA; i++) {
+               dc->sc_hwaddr = (i & 1) ? &dma->dma_chan1 : &dma->dma_chan0;
+               dc->sc_Bhwaddr = (i & 1) ? &dma->dma_Bchan1 : &dma->dma_Bchan0;
+               dc->sc_type = rev == 'B' ? DMA_B : DMA_C;
+               dc++;
+               dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
+       }
+       dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
+       timeout(dmatimo, (caddr_t)0, DMATIMO * hz);
+
+       printf("dma: 98620%c with 2 channels, %d bit DMA\n",
+              rev, rev == 'B' ? 16 : 32);
+}
+
+int
+dmareq(dq)
+       register struct devqueue *dq;
+{
+       register int i;
+       register int chan;
+       register int s = splbio();
+
+       chan = dq->dq_ctlr;
+       i = NDMA;
+       while (--i >= 0) {
+               if ((chan & (1 << i)) == 0)
+                       continue;
+               if (dmachan[i].dq_forw != &dmachan[i])
+                       continue;
+               insque(dq, &dmachan[i]);
+               dq->dq_ctlr = i;
+               splx(s);
+               return(1);
+       }
+       insque(dq, dmachan[NDMA].dq_back);
+       splx(s);
+       return(0);
+}
+
+void
+dmafree(dq)
+       register struct devqueue *dq;
+{
+       int unit = dq->dq_ctlr;
+       register struct dma_softc *dc = &dma_softc[unit];
+       register struct devqueue *dn;
+       register int chan, s;
+
+       s = splbio();
+       dc->sc_timo = 0;
+       DMA_CLEAR(dc);
+       remque(dq);
+       chan = 1 << unit;
+       for (dn = dmachan[NDMA].dq_forw;
+            dn != &dmachan[NDMA]; dn = dn->dq_forw) {
+               if (dn->dq_ctlr & chan) {
+                       remque((caddr_t)dn);
+                       insque((caddr_t)dn, (caddr_t)dq->dq_back);
+                       splx(s);
+                       dn->dq_ctlr = dq->dq_ctlr;
+                       (dn->dq_driver->d_start)(dn->dq_unit);
+                       return;
+               }
+       }
+       splx(s);
+}
+
+void
+dmago(unit, addr, count, flags)
+       int unit;
+       register char *addr;
+       register int count;
+       register int flags;
+{
+       register struct dma_softc *dc = &dma_softc[unit];
+       register char *dmaend = NULL;
+       register int tcount, i;
+
+#ifdef DEBUG
+       if (dmadebug & DDB_FOLLOW)
+               printf("dmago(%d, %x, %x, %x)\n",
+                      unit, addr, count, flags);
+       if (flags & DMAGO_LWORD)
+               dmalword[unit]++;
+       else if (flags & DMAGO_WORD)
+               dmaword[unit]++;
+       else
+               dmabyte[unit]++;
+#endif
+#if defined(HP320)
+       if (dc->sc_type == DMA_B && (flags & DMAGO_LWORD))
+               panic("dmago: no can do 32-bit DMA");
+#endif
+       /*
+        * Build the DMA chain
+        */
+       for (i = 0; i < DMAMAXIO && count; i++) {
+               dc->sc_addr[i] = (char *)kvtop(addr);
+               tcount = dc->sc_count[i] =
+                       MIN(count, NBPG - ((int)addr & PGOFSET));
+               addr += dc->sc_count[i];
+               count -= tcount;
+               if (flags & (DMAGO_WORD|DMAGO_LWORD))
+                       tcount >>= (flags & DMAGO_WORD) ? 1 : 2;
+               if (dc->sc_addr[i] == dmaend
+#if defined(HP320)
+                   /* only 16-bit count on 98620B */
+                   && (dc->sc_type != DMA_B ||
+                       dc->sc_count[i-1] + tcount <= 65536)
+#endif
+               ) {
+#ifdef DEBUG
+                       dmahits[unit]++;
+#endif
+                       dmaend += dc->sc_count[i];
+                       dc->sc_count[i-1] += tcount;
+                       i--;
+               } else {
+#ifdef DEBUG
+                       dmamisses[unit]++;
+#endif
+                       dmaend = dc->sc_addr[i] + dc->sc_count[i];
+                       dc->sc_count[i] = tcount;
+               }
+       }
+       if (count)
+               panic("dmago maxphys");
+       dc->sc_count[i] = 0;
+       dc->sc_cur = 0;
+       /*
+        * Set up the command word based on flags
+        */
+       dc->sc_cmd = DMA_ENAB | DMA_IPL(DMAINTLVL) | DMA_START;
+       if ((flags & DMAGO_READ) == 0)
+               dc->sc_cmd |= DMA_WRT;
+       if (flags & DMAGO_LWORD)
+               dc->sc_cmd |= DMA_LWORD;
+       else if (flags & DMAGO_WORD)
+               dc->sc_cmd |= DMA_WORD;
+       if (flags & DMAGO_PRI)
+               dc->sc_cmd |= DMA_PRI;
+
+       /*
+        * We should be able to skip the dma completion interrupt
+        * if we only have one segment in the chain since many
+        * devices generate their own completion interrupt.
+        * However, on a 370 we have to take the interrupt on
+        * read transfers to invalidate the external cache.
+        */
+       if ((flags & DMAGO_NOINT) && i == 1
+#if defined(HP370)
+           && ((flags & DMAGO_READ) == 0 || ectype != EC_PHYS)
+#endif
+       )
+               dc->sc_cmd &= ~DMA_ENAB;
+#ifdef DEBUG
+#if defined(HP320)
+       /* would this hurt? */
+       if (dc->sc_type == DMA_B)
+               dc->sc_cmd &= ~DMA_START;
+#endif
+       if (dmadebug & DDB_IO)
+               if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
+                   (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) {
+                       printf("dmago: cmd %x\n", dc->sc_cmd);
+                       for (i = 0; dc->sc_count[i]; i++) 
+                               printf("  %d: %d@%x\n",
+                                      i, dc->sc_count[i], dc->sc_addr[i]);
+               }
+#endif
+
+       /*
+        * Load and arm the channel
+        */
+       dc->sc_timo = 1;
+       DMA_ARM(dc, 0);
+}
+
+void
+dmastop(unit)
+       register int unit;
+{
+       register struct dma_softc *dc = &dma_softc[unit];
+       register struct devqueue *dq;
+
+#ifdef DEBUG
+       if (dmadebug & DDB_FOLLOW)
+               printf("dmastop(%d)\n", unit);
+#endif
+       dc->sc_timo = 0;
+       DMA_CLEAR(dc);
+
+       /*
+        * We may get this interrupt after a device service routine
+        * has freed the dma channel.  So, ignore the intr if there's
+        * nothing on the queue.
+        */
+       dq = dmachan[unit].dq_forw;
+       if (dq != &dmachan[unit]) {
+#if defined(HP370)
+               /*
+                * The 370 has an 64k external physical address cache.
+                * In theory, we should only need to flush it when
+                * DMAing to memory.
+                */
+               if (ectype == EC_PHYS && (dc->sc_cmd & DMA_WRT) == 0)
+                       PCIA();
+#endif
+               (dq->dq_driver->d_done)(dq->dq_unit);
+       }
+}
+
+int
+dmaintr()
+{
+       register struct dma_softc *dc;
+       register int i, j, stat;
+       int found = 0;
+
+#ifdef DEBUG
+       if (dmadebug & DDB_FOLLOW)
+               printf("dmaintr\n");
+#endif
+       for (i = 0, dc = dma_softc; i < NDMA; i++, dc++) {
+               stat = DMA_STAT(dc);
+               if ((stat & DMA_INTR) == 0)
+                       continue;
+               found++;
+#ifdef DEBUG
+               if (dmadebug & DDB_IO) {
+                       if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
+                           (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD))
+                               printf("dmaintr: unit %d stat %x next %d\n",
+                                      i, stat, dc->sc_cur+1);
+               }
+               if (stat & DMA_ARMED)
+                       printf("dma%d: intr when armed\n", i);
+#endif
+               j = ++dc->sc_cur;
+               if (j < DMAMAXIO && dc->sc_count[j]) {
+                       dc->sc_timo = 1;
+                       DMA_CLEAR(dc);
+                       DMA_ARM(dc, j);
+               } else
+                       dmastop(i);
+       }
+       return(found);
+}
+
+void
+dmatimo()
+{
+       register int i, s;
+       register struct dma_softc *dc = &dma_softc[0];
+
+       for (i = 0; i < NDMA; i++, dc++) {
+               s = splbio();
+               if (dc->sc_timo) {
+                       if (dc->sc_timo == 1)
+                               dc->sc_timo++;
+                       else
+                               dmastop(i);
+               }
+               splx(s);
+       }
+       timeout(dmatimo, (caddr_t)0, DMATIMO * hz);
+}
diff --git a/usr/src/sys/hp300/dev/dmareg.h b/usr/src/sys/hp300/dev/dmareg.h
new file mode 100644 (file)
index 0000000..d1e412f
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)dmareg.h    7.1 (Berkeley) %G%
+ */
+
+/*
+ * Hardware layout for the 98620[ABC]:
+ *     98620A (old 320s?):     byte/word DMA in up to 64K chunks
+ *     98620B (320s only):     98620A with programmable IPL
+ *     98620C (all others):    byte/word/longword DMA in up to 4Gb chunks
+ */
+#define v_char         volatile char
+#define        v_int           volatile int
+#define vu_char                volatile u_char
+#define vu_short       volatile u_short
+#define vu_int         volatile u_int
+
+struct dmaBdevice {
+       v_char          *dmaB_addr;
+       vu_short        dmaB_count;
+       vu_short        dmaB_cmd;
+#define        dmaB_stat       dmaB_cmd
+};
+
+struct dmadevice {
+       v_char          *dma_addr;
+       vu_int          dma_count;
+       vu_short        dma_cmd;
+       vu_short        dma_stat;
+};
+
+struct dmareg {
+       struct dmaBdevice dma_Bchan0;
+       struct dmaBdevice dma_Bchan1;
+/* the rest are 98620C specific */
+       v_char            dma_id[4];
+       vu_char           dma_cr;
+       char              dma_pad1[0xEB];
+       struct dmadevice  dma_chan0;
+       char              dma_pad2[0xF4];
+       struct dmadevice  dma_chan1;
+};
+
+#define        NDMA            2
+
+/* intr level must be >= level of any device using dma.  i.e., splbio */
+#define        DMAINTLVL       5
+
+/* addresses */
+#define        DMA_BASE        IOV(0x500000)
+
+/* command bits */
+#define        DMA_ENAB        0x0001
+#define        DMA_WORD        0x0002
+#define        DMA_WRT         0x0004
+#define        DMA_PRI         0x0008
+#define        DMA_IPL(x)      (((x) - 3) << 4)
+#define DMA_LWORD      0x0100
+#define DMA_START      0x8000
+
+/* status bits */
+#define        DMA_ARMED       0x01
+#define        DMA_INTR        0x02
+#define DMA_ACC                0x04
+#define DMA_HALT       0x08
+#define DMA_BERR       0x10
+#define DMA_ALIGN      0x20
+#define DMA_WRAP       0x40
+
+#ifdef KERNEL
+/*
+ * Macros to attempt to hide the HW differences between the 98620B DMA
+ * board and the 1TQ4-0401 DMA chip (68020C "board").  The latter
+ * includes emulation registers for the former but you need to access
+ * the "native-mode" registers directly in order to do 32-bit DMA.
+ *
+ * DMA_CLEAR:  Clear interrupt on DMA board.  We just use the
+ *             emulation registers on the 98620C as that is easiest.
+ * DMA_STAT:   Read status register.  Again, we always read the
+ *             emulation register.  Someday we might want to
+ *             look at the 98620C status to get the extended bits.
+ * DMA_ARM:    Load address, count and kick-off DMA.
+ */
+#define        DMA_CLEAR(dc)   { v_int dmaclr = (int)dc->sc_Bhwaddr->dmaB_addr; }
+#define        DMA_STAT(dc)    dc->sc_Bhwaddr->dmaB_stat
+
+#if defined(HP320)
+#define        DMA_ARM(dc, ix) \
+       if (dc->sc_type == DMA_B) { \
+               register struct dmaBdevice *dma = dc->sc_Bhwaddr; \
+               dma->dmaB_addr = dc->sc_addr[ix]; \
+               dma->dmaB_count = dc->sc_count[ix] - 1; \
+               dma->dmaB_cmd = dc->sc_cmd; \
+       } else { \
+               register struct dmadevice *dma = dc->sc_hwaddr; \
+               dma->dma_addr = dc->sc_addr[ix]; \
+               dma->dma_count = dc->sc_count[ix] - 1; \
+               dma->dma_cmd = dc->sc_cmd; \
+       }
+#else
+#define        DMA_ARM(dc, ix) \
+       { \
+               register struct dmadevice *dma = dc->sc_hwaddr; \
+               dma->dma_addr = dc->sc_addr[ix]; \
+               dma->dma_count = dc->sc_count[ix] - 1; \
+               dma->dma_cmd = dc->sc_cmd; \
+       }
+#endif
+#endif
diff --git a/usr/src/sys/hp300/dev/dmavar.h b/usr/src/sys/hp300/dev/dmavar.h
new file mode 100644 (file)
index 0000000..737db57
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)dmavar.h    7.1 (Berkeley) %G%
+ */
+
+/* dmago flags */
+#define DMAGO_BYTE     0x00
+#define DMAGO_WORD     0x01
+#define DMAGO_LWORD    0x02
+#define        DMAGO_PRI       0x04
+#define        DMAGO_READ      0x08
+#define        DMAGO_NOINT     0x80
+
+/* dma "controllers" (channels) */
+#define        DMA0            0x1
+#define        DMA1            0x2
+
+#ifdef KERNEL
+extern void    dmago(), dmafree();
+extern int     dmareq();
+#endif
diff --git a/usr/src/sys/hp300/dev/fhpib.c b/usr/src/sys/hp300/dev/fhpib.c
new file mode 100644 (file)
index 0000000..ca86d58
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)fhpib.c     7.1 (Berkeley) %G%
+ */
+
+/*
+ * 98625A/B HPIB driver
+ */
+#include "hpib.h"
+#if NHPIB > 0
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "device.h"
+#include "fhpibreg.h"
+#include "hpibvar.h"
+#include "dmavar.h"
+
+/*
+ * Inline version of fhpibwait to be used in places where
+ * we don't worry about getting hung.
+ */
+#define        FHPIBWAIT(hd, m)        while (((hd)->hpib_intr & (m)) == 0)
+
+#ifdef DEBUG
+int    fhpibdebugunit = -1;
+int    fhpibdebug = 0;
+#define FDB_FAIL       0x01
+#define FDB_DMA                0x02
+#define FDB_WAIT       0x04
+#define FDB_PPOLL      0x08
+
+int    dopriodma = 0;  /* use high priority DMA */
+int    doworddma = 1;  /* non-zero if we should attempt word dma */
+int    dolworddma = 1; /* use longword dma (scsi) */
+int    doppollint = 1; /* use ppoll interrupts instead of watchdog */
+
+long   fhpibbadint[2] = { 0 };
+long   fhpibtransfer[NHPIB] = { 0 };
+long   fhpibnondma[NHPIB] = { 0 };
+long   fhpibworddma[NHPIB] = { 0 };
+long   fhpibremain[NHPIB] = { 0 };
+long   fhpibloops[NHPIB] = { 0 };
+
+#endif
+
+int    fhpibcmd[NHPIB];
+int    dmathresh = 3;  /* char count beyond which we will attempt dma */
+
+extern int hpibtimeout;
+
+fhpibtype(hc)
+       register struct hp_ctlr *hc;
+{
+       register struct hpib_softc *hs = &hpib_softc[hc->hp_unit];
+       register struct fhpibdevice *hd = (struct fhpibdevice *)hc->hp_addr;
+
+       if (hd->hpib_cid != HPIBC)
+               return(0);
+       hs->sc_type = HPIBC;
+       hs->sc_ba = HPIBC_BA;
+       hc->hp_ipl = HPIB_IPL(hd->hpib_ids);
+       return(1);
+}
+
+fhpibreset(unit)
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_cid = 0xFF;
+       DELAY(100);
+       hd->hpib_cmd = CT_8BIT;
+       hd->hpib_ar = AR_ARONC;
+       fhpibifc(hd);
+       hd->hpib_ie = IDS_IE;
+       hd->hpib_data = C_DCL;
+       DELAY(100000);
+       /*
+        * See if we can do word dma.
+        * If so, we should be able to write and read back the appropos bit.
+        */
+       hd->hpib_ie |= IDS_WDMA;
+       if (hd->hpib_ie & IDS_WDMA) {
+               hd->hpib_ie &= ~IDS_WDMA;
+               hs->sc_flags |= HPIBF_DMA16;
+#ifdef DEBUG
+               if (fhpibdebug & FDB_DMA)
+                       printf("fhpibtype: unit %d has word dma\n", unit);
+
+#endif
+       }
+}
+
+fhpibifc(hd)
+       register struct fhpibdevice *hd;
+{
+       hd->hpib_cmd |= CT_IFC;
+       hd->hpib_cmd |= CT_INITFIFO;
+       DELAY(100);
+       hd->hpib_cmd &= ~CT_IFC;
+       hd->hpib_cmd |= CT_REN;
+       hd->hpib_stat = ST_ATN;
+}
+
+fhpibsend(unit, slave, sec, addr, cnt)
+       register char *addr;
+       register int cnt;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+       register int timo;
+       int origcnt = cnt;
+       int err = 0;
+
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_stat = 0;
+       hd->hpib_imask = IM_IDLE | IM_ROOM;
+       if (fhpibwait(hd, IM_IDLE) < 0)
+               err++;
+       hd->hpib_stat = ST_ATN;
+       hd->hpib_data = C_UNL;
+       hd->hpib_data = C_TAG + hs->sc_ba;
+       hd->hpib_data = C_LAG + slave;
+       if (sec != -1)
+               hd->hpib_data = C_SCG + sec;
+       if (fhpibwait(hd, IM_IDLE) < 0)
+               err++;
+       hd->hpib_stat = ST_WRITE;
+       if (cnt && !err) {
+               while (--cnt) {
+                       hd->hpib_data = *addr++;
+                       timo = hpibtimeout;
+                       while ((hd->hpib_intr & IM_ROOM) == 0)
+                               if (--timo == 0) {
+                                       err++;
+                                       goto out;
+                               }
+               }
+               hd->hpib_stat = ST_EOI;
+               hd->hpib_data = *addr;
+               FHPIBWAIT(hd, IM_ROOM);
+               hd->hpib_stat = ST_ATN;
+               /* XXX: HP-UX claims bug with CS80 transparent messages */
+               if (sec == 0x12)
+                       DELAY(150);
+               hd->hpib_data = C_UNL;
+               if (fhpibwait(hd, IM_IDLE) < 0)
+                       err++;
+       }
+out:
+       if (err) {
+               cnt++;
+               fhpibifc(hd);
+#ifdef DEBUG
+               if (fhpibdebug & FDB_FAIL) {
+                       printf("hpib%d: fhpibsend failed: slave %d, sec %x, ",
+                              unit, slave, sec);
+                       printf("sent %d of %d bytes\n", origcnt-cnt, origcnt);
+               }
+#endif
+       }
+       hd->hpib_imask = 0;
+       return(origcnt - cnt);
+}
+
+fhpibrecv(unit, slave, sec, addr, cnt)
+       register char *addr;
+       register int cnt;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+       register int timo;
+       int origcnt = cnt;
+       int err = 0;
+
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_stat = 0;
+       hd->hpib_imask = IM_IDLE | IM_ROOM | IM_BYTE;
+       if (fhpibwait(hd, IM_IDLE) < 0)
+               err++;
+       hd->hpib_stat = ST_ATN;
+       hd->hpib_data = C_UNL;
+       hd->hpib_data = C_LAG + hs->sc_ba;
+       hd->hpib_data = C_TAG + slave;
+       if (sec != -1)
+               hd->hpib_data = C_SCG + sec;
+       if (fhpibwait(hd, IM_IDLE) < 0)
+               err++;
+       hd->hpib_stat = ST_READ0;
+       hd->hpib_data = 0;
+       if (cnt && !err) {
+               do {
+                       timo = hpibtimeout;
+                       while ((hd->hpib_intr & IM_BYTE) == 0)
+                               if (--timo == 0) {
+                                       err++;
+                                       goto out;
+                               }
+                       *addr++ = hd->hpib_data;
+               } while (--cnt);
+out:
+               FHPIBWAIT(hd, IM_ROOM);
+               hd->hpib_stat = ST_ATN;
+               hd->hpib_data = (slave == 31) ? C_UNA : C_UNT;
+               if (fhpibwait(hd, IM_IDLE) < 0)
+                       err++;
+       }
+       if (err) {
+               if (!cnt)
+                       cnt++;
+               fhpibifc(hd);
+#ifdef DEBUG
+               if (fhpibdebug & FDB_FAIL) {
+                       printf("hpib%d: fhpibrecv failed: slave %d, sec %x, ",
+                              unit, slave, sec);
+                       printf("got %d of %d bytes\n", origcnt-cnt, origcnt);
+               }
+#endif
+       }
+       hd->hpib_imask = 0;
+       return(origcnt - cnt);
+}
+
+fhpibgo(unit, slave, sec, addr, count, rw)
+       register int unit;
+       char *addr;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+       register int i;
+       int flags = 0;
+
+#ifdef lint
+       i = unit; if (i) return;
+#endif
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       hs->sc_flags |= HPIBF_IO;
+       if (rw == B_READ)
+               hs->sc_flags |= HPIBF_READ;
+#ifdef DEBUG
+       else if (hs->sc_flags & HPIBF_READ) {
+               printf("fhpibgo: HPIBF_READ still set\n");
+               hs->sc_flags &= ~HPIBF_READ;
+       }
+#endif
+       hs->sc_count = count;
+       hs->sc_addr = addr;
+#ifdef DEBUG
+       fhpibtransfer[unit]++;
+#endif
+       if ((hs->sc_flags & HPIBF_DMA16) &&
+           ((int)addr & 1) == 0 && count && (count & 1) == 0
+#ifdef DEBUG
+           && doworddma
+#endif
+           ) {
+#ifdef DEBUG
+               fhpibworddma[unit]++;
+#endif
+               flags |= DMAGO_WORD;
+               hd->hpib_latch = 0;
+       }
+#ifdef DEBUG
+       if (dopriodma)
+               flags |= DMAGO_PRI;
+#endif
+       if (hs->sc_flags & HPIBF_READ) {
+               fhpibcmd[unit] = CT_REN | CT_8BIT;
+               hs->sc_curcnt = count;
+               dmago(hs->sc_dq.dq_ctlr, addr, count, flags|DMAGO_READ);
+               if (fhpibrecv(unit, slave, sec, 0, 0) < 0) {
+#ifdef DEBUG
+                       printf("fhpibgo: recv failed, retrying...\n");
+#endif
+                       (void) fhpibrecv(unit, slave, sec, 0, 0);
+               }
+               i = hd->hpib_cmd;
+               hd->hpib_cmd = fhpibcmd[unit];
+               hd->hpib_ie = IDS_DMA(hs->sc_dq.dq_ctlr) |
+                       ((flags & DMAGO_WORD) ? IDS_WDMA : 0);
+               return;
+       }
+       fhpibcmd[unit] = CT_REN | CT_8BIT | CT_FIFOSEL;
+       if (count < dmathresh) {
+#ifdef DEBUG
+               fhpibnondma[unit]++;
+               fhpibworddma[unit]--;
+#endif
+               hs->sc_curcnt = count;
+               (void) fhpibsend(unit, slave, sec, addr, count);
+               fhpibdone(unit);
+               return;
+       }
+       count -= (flags & DMAGO_WORD) ? 2 : 1;
+       hs->sc_curcnt = count;
+       dmago(hs->sc_dq.dq_ctlr, addr, count, flags);
+       if (fhpibsend(unit, slave, sec, 0, 0) < 0) {
+#ifdef DEBUG
+               printf("fhpibgo: send failed, retrying...\n");
+#endif
+               (void) fhpibsend(unit, slave, sec, 0, 0);
+       }
+       i = hd->hpib_cmd;
+       hd->hpib_cmd = fhpibcmd[unit];
+       hd->hpib_ie = IDS_DMA(hs->sc_dq.dq_ctlr) | IDS_WRITE |
+               ((flags & DMAGO_WORD) ? IDS_WDMA : 0);
+}
+
+fhpibdone(unit)
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+       register char *addr;
+       register int cnt;
+
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       cnt = hs->sc_curcnt;
+       hs->sc_addr += cnt;
+       hs->sc_count -= cnt;
+#ifdef DEBUG
+       if ((fhpibdebug & FDB_DMA) && fhpibdebugunit == unit)
+               printf("fhpibdone: addr %x cnt %d\n",
+                      hs->sc_addr, hs->sc_count);
+#endif
+       if (hs->sc_flags & HPIBF_READ)
+               hd->hpib_imask = IM_IDLE | IM_BYTE;
+       else {
+               cnt = hs->sc_count;
+               if (cnt) {
+                       addr = hs->sc_addr;
+                       hd->hpib_imask = IM_IDLE | IM_ROOM;
+#ifdef DEBUG
+                       fhpibremain[unit]++;
+                       while ((hd->hpib_intr & IM_IDLE) == 0)
+                               fhpibloops[unit]++;
+#else
+                       FHPIBWAIT(hd, IM_IDLE);
+#endif
+                       hd->hpib_stat = ST_WRITE;
+                       while (--cnt) {
+                               hd->hpib_data = *addr++;
+                               FHPIBWAIT(hd, IM_ROOM);
+                       }
+                       hd->hpib_stat = ST_EOI;
+                       hd->hpib_data = *addr;
+               }
+               hd->hpib_imask = IM_IDLE;
+       }
+       hs->sc_flags |= HPIBF_DONE;
+       hd->hpib_stat = ST_IENAB;
+       hd->hpib_ie = IDS_IE;
+}
+
+fhpibintr(unit)
+       register int unit;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+       register struct devqueue *dq;
+       register int stat0;
+
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       stat0 = hd->hpib_ids;
+       if ((stat0 & (IDS_IE|IDS_IR)) != (IDS_IE|IDS_IR)) {
+#ifdef DEBUG
+               if ((fhpibdebug & FDB_FAIL) && (stat0 & IDS_IR) &&
+                   (hs->sc_flags & (HPIBF_IO|HPIBF_DONE)) != HPIBF_IO)
+                       printf("hpib%d: fhpibintr: bad status %x\n",
+                              unit, stat0);
+               fhpibbadint[0]++;
+#endif
+               return(0);
+       }
+       if ((hs->sc_flags & (HPIBF_IO|HPIBF_DONE)) == HPIBF_IO) {
+#ifdef DEBUG
+               fhpibbadint[1]++;
+#endif
+               return(0);
+       }
+#ifdef DEBUG
+       if ((fhpibdebug & FDB_DMA) && fhpibdebugunit == unit)
+               printf("fhpibintr: flags %x\n", hs->sc_flags);
+#endif
+       dq = hs->sc_sq.dq_forw;
+       if (hs->sc_flags & HPIBF_IO) {
+               stat0 = hd->hpib_cmd;
+               hd->hpib_cmd = fhpibcmd[unit] & ~CT_8BIT;
+               hd->hpib_stat = 0;
+               hd->hpib_cmd = CT_REN | CT_8BIT;
+               stat0 = hd->hpib_intr;
+               hd->hpib_imask = 0;
+               hs->sc_flags &= ~(HPIBF_DONE|HPIBF_IO|HPIBF_READ);
+               dmafree(&hs->sc_dq);
+               (dq->dq_driver->d_intr)(dq->dq_unit);
+       } else if (hs->sc_flags & HPIBF_PPOLL) {
+               stat0 = hd->hpib_intr;
+#ifdef DEBUG
+               if ((fhpibdebug & FDB_FAIL) &&
+                   doppollint && (stat0 & IM_PPRESP) == 0)
+                       printf("hpib%d: fhpibintr: bad intr reg %x\n",
+                              unit, stat0);
+#endif
+               hd->hpib_stat = 0;
+               hd->hpib_imask = 0;
+#ifdef DEBUG
+               stat0 = fhpibppoll(unit);
+               if ((fhpibdebug & FDB_PPOLL) && unit == fhpibdebugunit)
+                       printf("fhpibintr: got PPOLL status %x\n", stat0);
+               if ((stat0 & (0x80 >> dq->dq_slave)) == 0) {
+                       printf("fhpibintr: PPOLL: unit %d slave %d stat %x\n",
+                              unit, dq->dq_slave, stat0);
+                       return(1);
+               }
+#endif
+               hs->sc_flags &= ~HPIBF_PPOLL;
+               (dq->dq_driver->d_intr)(dq->dq_unit);
+       }
+       return(1);
+}
+
+fhpibppoll(unit)
+{
+       register struct fhpibdevice *hd;
+       register int ppoll;
+
+       hd = (struct fhpibdevice *)hpib_softc[unit].sc_hc->hp_addr;
+       hd->hpib_stat = 0;
+       hd->hpib_psense = 0;
+       hd->hpib_pmask = 0xFF;
+       hd->hpib_imask = IM_PPRESP | IM_PABORT;
+       DELAY(25);
+       hd->hpib_intr = IM_PABORT;
+       ppoll = hd->hpib_data;
+       if (hd->hpib_intr & IM_PABORT)
+               ppoll = 0;
+       hd->hpib_imask = 0;
+       hd->hpib_pmask = 0;
+       hd->hpib_stat = ST_IENAB;
+       return(ppoll);
+}
+
+fhpibwait(hd, x)
+       register struct fhpibdevice *hd;
+{
+       register int timo = hpibtimeout;
+
+       while ((hd->hpib_intr & x) == 0 && --timo)
+               ;
+       if (timo == 0) {
+#ifdef DEBUG
+               if (fhpibdebug & FDB_FAIL)
+                       printf("fhpibwait(%x, %x) timeout\n", hd, x);
+#endif
+               return(-1);
+       }
+       return(0);
+}
+
+/*
+ * XXX: this will have to change if we every allow more than one
+ * pending operation per HP-IB.
+ */
+fhpibppwatch(unit)
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct fhpibdevice *hd;
+       register int slave;
+
+       if ((hs->sc_flags & HPIBF_PPOLL) == 0)
+               return;
+       hd = (struct fhpibdevice *)hs->sc_hc->hp_addr;
+       slave = (0x80 >> hs->sc_sq.dq_forw->dq_slave);
+#ifdef DEBUG
+       if (!doppollint) {
+               if (fhpibppoll(unit) & slave) {
+                       hd->hpib_stat = ST_IENAB;
+                       hd->hpib_imask = IM_IDLE | IM_ROOM;
+               } else
+                       timeout(fhpibppwatch, unit, 1);
+               return;
+       }
+       if ((fhpibdebug & FDB_PPOLL) && unit == fhpibdebugunit)
+               printf("fhpibppwatch: sense request on %d\n", unit);
+#endif
+       hd->hpib_psense = ~slave;
+       hd->hpib_pmask = slave;
+       hd->hpib_stat = ST_IENAB;
+       hd->hpib_imask = IM_PPRESP | IM_PABORT;
+       hd->hpib_ie = IDS_IE;
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/fhpibreg.h b/usr/src/sys/hp300/dev/fhpibreg.h
new file mode 100644 (file)
index 0000000..8c4b258
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)fhpibreg.h  7.1 (Berkeley) %G%
+ */
+
+#define        vu_char volatile u_char
+
+struct fhpibdevice {
+       u_char  hpib_pad0;
+       vu_char hpib_cid;
+       u_char  hpib_pad1;
+#define        hpib_ie         hpib_ids
+       vu_char hpib_ids;
+       u_char  hpib_pad2;
+       vu_char hpib_ctrl2;
+       u_char  hpib_pad3;
+       vu_char hpib_latch;
+       u_char  hpib_pad4[9];
+       vu_char hpib_intr;
+       u_char  hpib_pad5;
+       vu_char hpib_imask;
+       u_char  hpib_pad6;
+       vu_char hpib_data;
+       u_char  hpib_pad7;
+       vu_char hpib_stat;
+       u_char  hpib_pad8;
+       vu_char hpib_cmd;
+       u_char  hpib_pad9;
+       vu_char hpib_ar;
+       u_char  hpib_pad10;
+       vu_char hpib_pmask;
+       u_char  hpib_pad11;
+       vu_char hpib_psense;
+};
+
+/* status bits */
+#define        ST_READ0        0xC0
+#define        ST_READ1        0x80
+#define        ST_IENAB        0x80
+#define        ST_EOI          0x80
+#define        ST_ATN          0x40
+#define        ST_WRITE        0x00
+
+/* control bits */
+#define        CT_8BIT         0x80
+#define        CT_REN          0x20
+#define        CT_IFC          0x10
+#define        CT_FIFOSEL      0x02
+#define        CT_INITFIFO     0x01
+
+#define        IM_PABORT       0x40
+#define        IM_PPRESP       0x20
+#define        IM_ROOM         0x08
+#define        IM_BYTE         0x04
+#define        IM_IDLE         0x02
+
+#define        AR_ARONC        0x80
diff --git a/usr/src/sys/hp300/dev/grf_dv.c b/usr/src/sys/hp300/dev/grf_dv.c
new file mode 100644 (file)
index 0000000..6954384
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_dv.c 1.6 89/04/11$
+ *
+ *     @(#)grf_dv.c    7.1 (Berkeley) %G%
+ */
+
+#include "grf.h"
+#if NGRF > 0
+
+/*
+ * Graphics routines for the DaVinci, HP98730/98731 Graphics system.
+ */
+#include "param.h"
+#include "errno.h"
+
+#include "grfioctl.h"
+#include "grfvar.h"
+#include "grf_dvreg.h"
+
+#include "machine/cpu.h"
+
+/*
+ * Initialize hardware.
+ * Must point g_display at a grfinfo structure describing the hardware.
+ * Returns 0 if hardware not present, non-zero ow.
+ */
+dv_init(gp, addr)
+       struct grf_softc *gp;
+       u_char *addr;
+{
+       register struct dvboxfb *dbp;
+       struct grfinfo *gi = &gp->g_display;
+       int fboff;
+
+       dbp = (struct dvboxfb *) addr;
+       gi->gd_regaddr = (caddr_t) UNIOV(addr);
+       gi->gd_regsize = 0x20000;
+       gi->gd_fbwidth = (dbp->fbwmsb << 8) | dbp->fbwlsb;
+       gi->gd_fbheight = (dbp->fbhmsb << 8) | dbp->fbhlsb;
+       fboff = (dbp->fbomsb << 8) | dbp->fbolsb;
+       gi->gd_fbaddr = (caddr_t) (*(addr + fboff) << 16);
+       gi->gd_fbsize = gi->gd_fbwidth * gi->gd_fbheight;
+       gi->gd_dwidth = (dbp->dwmsb << 8) | dbp->dwlsb;
+       gi->gd_dheight = (dbp->dwmsb << 8) | dbp->dwlsb;
+       gi->gd_planes = 0;      /* ?? */
+       gi->gd_colors = 256;
+
+       dv_reset(dbp);
+       return(1);
+}
+
+/*
+ *  Magic code herein.
+ */
+dv_reset(dbp)
+       register struct dvboxfb *dbp;
+{
+       dbp->reset = 0x80;
+       DELAY(100);
+
+       dbp->interrupt = 0x04;
+       dbp->en_scan   = 0x01;
+       dbp->fbwen     = ~0;
+       dbp->opwen     = ~0;
+       dbp->fold      = 0x01;
+       dbp->drive     = 0x01;
+       dbp->rep_rule  = 0x33;
+       dbp->alt_rr    = 0x33;
+       dbp->zrr       = 0x33;
+
+       dbp->fbvenp    = 0xFF;
+       dbp->dispen    = 0x01;
+       dbp->fbvens    = 0x0;
+       dbp->fv_trig   = 0x01;
+       DELAY(100);
+       dbp->vdrive    = 0x0;
+       dbp->zconfig   = 0x0;
+
+       while (dbp->wbusy & 0x01)
+         DELAY(100);
+
+       dbp->cmapbank = 0;
+
+       dbp->red0   = 0;
+       dbp->red1   = 0;
+       dbp->green0 = 0;
+       dbp->green1 = 0;
+       dbp->blue0  = 0;
+       dbp->blue1  = 0;
+
+       dbp->panxh   = 0;
+       dbp->panxl   = 0;
+       dbp->panyh   = 0;
+       dbp->panyl   = 0;
+       dbp->zoom    = 0;
+       dbp->cdwidth = 0x50;
+       dbp->chstart = 0x52;
+       dbp->cvwidth = 0x22;
+       dbp->pz_trig = 1;
+}
+
+/*
+ * Change the mode of the display.
+ * Right now all we can do is grfon/grfoff.
+ * Return a UNIX error number or 0 for success.
+ */
+dv_mode(gp, cmd)
+       register struct grf_softc *gp;
+{
+       register struct dvboxfb *dbp;
+       int error = 0;
+
+       dbp = (struct dvboxfb *) IOV(gp->g_display.gd_regaddr);
+       switch (cmd) {
+       case GM_GRFON:
+               dbp->dispen = 0x01;
+               break;
+       case GM_GRFOFF:
+               break;
+       case GM_GRFOVON:
+               dbp->opwen = 0xF;
+               dbp->drive = 0x10;
+               break;
+       case GM_GRFOVOFF:
+               dbp->opwen = 0;
+               dbp->drive = 0x01;
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return(error);
+}
+
+#endif
diff --git a/usr/src/sys/hp300/dev/grf_dvreg.h b/usr/src/sys/hp300/dev/grf_dvreg.h
new file mode 100644 (file)
index 0000000..8375c4d
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_dvreg.h 1.4 89/08/25$
+ *
+ *     @(#)grf_dvreg.h 7.1 (Berkeley) %G%
+ */
+
+/*
+ * Map of the DaVinci frame buffer controller chip in memory ...
+ */
+
+#define db_waitbusy(regaddr) \
+       while (((struct dvboxfb *)(regaddr))->wbusy || \
+              ((struct dvboxfb *)(regaddr))->as_busy) DELAY(100)
+
+#define        vu_char         volatile u_char
+#define        vu_short        volatile u_short
+#define        vu_int          volatile u_int
+
+struct rgb {
+  u_char :8, :8, :8;
+  vu_char red;
+  u_char :8, :8, :8;
+  vu_char green;
+  u_char :8, :8, :8;
+  vu_char blue;
+};
+
+struct dvboxfb {
+  u_char       :8;
+  vu_char      reset;                  /* reset register               0x01 */
+  u_char       fb_address;             /* frame buffer address         0x02 */
+  vu_char      interrupt;              /* interrupt register           0x03 */
+  u_char       :8;
+  vu_char      fbwmsb;                 /* frame buffer width MSB       0x05 */
+  u_char       :8;
+  vu_char      fbwlsb;                 /* frame buffer width MSB       0x07 */
+  u_char       :8;
+  vu_char      fbhmsb;                 /* frame buffer height MSB      0x09 */
+  u_char       :8;
+  vu_char      fbhlsb;                 /* frame buffer height MSB      0x0b */
+  u_char       :8;
+  vu_char      dwmsb;                  /* display width MSB            0x0d */
+  u_char       :8;
+  vu_char      dwlsb;                  /* display width MSB            0x0f */
+  u_char       :8;
+  vu_char      dhmsb;                  /* display height MSB           0x11 */
+  u_char       :8;
+  vu_char      dhlsb;                  /* display height MSB           0x13 */
+  u_char       :8;
+  vu_char      fbid;                   /* frame buffer id              0x15 */
+  u_char       f1[0x47];
+  vu_char      fbomsb;                 /* frame buffer offset MSB      0x5d */
+  u_char       :8;
+  vu_char      fbolsb;                 /* frame buffer offset LSB      0x5f */
+  u_char       f2[16359];
+  vu_char      wbusy;                  /* Window move in progress    0x4047 */
+  u_char       f3[0x405b-0x4047-1];
+  vu_char      as_busy;                /* Scan accessing frame buf.  0x405B */
+  u_char        f4[0x4090-0x405b-1];
+  vu_int       fbwen;                  /* Frame buffer write enable  0x4090 */
+  u_char       f5[0x409f-0x4090-4];
+  vu_char      wmove;                  /* Initiate window move.      0x409F */
+  u_char       f6[0x40b3-0x409f-1];
+  vu_char      fold;                   /* Byte/longword per pixel    0x40B3 */
+  u_char       f7[0x40b7-0x40b3-1];
+  vu_char      opwen;                  /* Overlay plane write enable 0x40B7 */
+  u_char       f8[0x40bf-0x40b7-1];
+  vu_char      drive;                  /* Select FB vs. Overlay.     0x40BF */
+
+  u_char        f8a[0x40cb-0x40bf-1];
+  vu_char      zconfig;                /* Z buffer configuration     0x40CB */
+  u_char       f8b[0x40cf-0x40cb-1];
+  vu_char      alt_rr;                 /* Alternate replacement rule 0x40CF */
+  u_char       f8c[0x40d3-0x40cf-1];
+  vu_char      zrr;                    /* Z replacement rule         0x40D3 */
+
+  u_char       f9[0x40d7-0x40d3-1];
+  vu_char      en_scan;                /* Enable scan DTACK.         0x40D7 */
+  u_char       f10[0x40ef-0x40d7-1];
+  vu_char      rep_rule;               /* Replacement rule           0x40EF */
+  u_char       f11[0x40f2-0x40ef-1];
+  vu_short     source_x;               /* Window source X origin     0x40F2 */
+  u_char       f12[0x40f6-0x40f2-2];
+  vu_short     source_y;               /* Window source Y origin     0x40F6 */
+  u_char       f13[0x40fa-0x40f6-2];
+  vu_short     dest_x;                 /* Window dest X origin       0x40FA */
+  u_char       f14[0x40fe-0x40fa-2];
+  vu_short     dest_y;                 /* Window dest Y origin       0x40FE */
+  u_char       f15[0x4102-0x40fe-2];
+  vu_short     wwidth;                 /* Window width               0x4102 */
+  u_char       f16[0x4106-0x4102-2];
+  vu_short     wheight;                /* Window height              0x4106 */
+  u_char       f17[0x6003-0x4106-2];
+  vu_char      cmapbank;               /* Bank select (0 or 1)       0x6003 */
+  u_char       f18[0x6007-0x6003-1];
+  vu_char      dispen;                 /* Display enable             0x6007 */
+
+  u_char       f18a[0x600B-0x6007-1];
+  vu_char      fbvenp;                 /* Frame buffer video enable  0x600B */
+  u_char       f18b[0x6017-0x600B-1];
+  vu_char      fbvens;                 /* fbvenp blink counterpart   0x6017 */
+
+  u_char       f19[0x6023-0x6017-1];
+  vu_char      vdrive;                 /* Video display mode         0x6023 */
+  u_char       f20[0x6083-0x6023-1];
+  vu_char      panxh;                  /* Pan display in X (high)    0x6083 */
+  u_char       f21[0x6087-0x6083-1];
+  vu_char      panxl;                  /* Pan display in X (low)     0x6087 */
+  u_char       f22[0x608b-0x6087-1];
+  vu_char      panyh;                  /* Pan display in Y (high)    0x608B */
+  u_char       f23[0x608f-0x608b-1];
+  vu_char      panyl;                  /* Pan display in Y (low)     0x608F */
+  u_char       f24[0x6093-0x608f-1];
+  vu_char      zoom;                   /* Zoom factor                0x6093 */
+  u_char       f25[0x6097-0x6093-1];
+  vu_char      pz_trig;                /* Pan & zoom trigger         0x6097 */
+  u_char       f26[0x609b-0x6097-1];
+  vu_char      ovly0p;                 /* Overlay 0 primary map      0x609B */
+  u_char       f27[0x609f-0x609b-1];
+  vu_char      ovly1p;                 /* Overlay 1 primary map      0x609F */
+  u_char       f28[0x60a3-0x609f-1];
+  vu_char      ovly0s;                 /* Overlay 0 secondary map    0x60A3 */
+  u_char       f29[0x60a7-0x60a3-1];
+  vu_char      ovly1s;                 /* Overlay 1 secondary map    0x60A7 */
+  u_char       f30[0x60ab-0x60a7-1];
+  vu_char      opvenp;                 /* Overlay video enable       0x60AB */
+  u_char       f31[0x60af-0x60ab-1];
+  vu_char      opvens;                 /* Overlay blink enable       0x60AF */
+  u_char       f32[0x60b3-0x60af-1];
+  vu_char      fv_trig;                /* Trigger control registers  0x60B3 */
+  u_char       f33[0x60b7-0x60b3-1];
+  vu_char      cdwidth;                /* Iris cdwidth timing reg.   0x60B7 */
+  u_char       f34[0x60bb-0x60b7-1];
+  vu_char      chstart;                /* Iris chstart timing reg.   0x60BB */
+  u_char       f35[0x60bf-0x60bb-1];
+  vu_char      cvwidth;                /* Iris cvwidth timing reg.   0x60BF */
+  u_char       f36[0x6100-0x60bf-1];
+  struct       rgb rgb[8];             /* overlay color map */
+  u_char       f37[0x6403-0x6100-sizeof(struct rgb)*8];
+  vu_char      red0;
+  u_char       f38[0x6803-0x6403-1];
+  vu_char      green0;
+  u_char       f39[0x6c03-0x6803-1];
+  vu_char      blue0;
+  u_char       f40[0x7403-0x6c03-1];
+  vu_char      red1;
+  u_char       f41[0x7803-0x7403-1];
+  vu_char      green1;
+  u_char       f42[0x7c03-0x7803-1];
+  vu_char      blue1;
+  u_char       f43[0x8012-0x7c03-1];
+  vu_short     status1;                /* Master Status register     0x8012 */
+  u_char       f44[0xC226-0x8012-2];
+  vu_short     trans;                  /* Transparency               0xC226 */
+  u_char       f45[0xC23E-0xC226-2];
+  vu_short     pstop;                  /* Pace value control         0xc23e */
+};
diff --git a/usr/src/sys/hp300/dev/grf_gb.c b/usr/src/sys/hp300/dev/grf_gb.c
new file mode 100644 (file)
index 0000000..e85d2f8
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_gb.c 1.13 89/04/11$
+ *
+ *     @(#)grf_gb.c    7.1 (Berkeley) %G%
+ */
+
+#include "grf.h"
+#if NGRF > 0
+
+/*
+ * Graphics routines for the Gatorbox.
+ *
+ * Note: In the context of this system, "gator" and "gatorbox" both refer to
+ *       HP 987x0 graphics systems.  "Gator" is not used for high res mono.
+ *       (as in 9837 Gator systems)
+ */
+#include "param.h"
+#include "errno.h"
+
+#include "grfioctl.h"
+#include "grfvar.h"
+#include "grf_gbreg.h"
+
+#include "machine/cpu.h"
+
+#define CRTC_DATA_LENGTH  0x0e
+u_char crtc_init_data[CRTC_DATA_LENGTH] = {
+    0x29, 0x20, 0x23, 0x04, 0x30, 0x0b, 0x30,
+    0x30, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * Initialize hardware.
+ * Must point g_display at a grfinfo structure describing the hardware.
+ * Returns 0 if hardware not present, non-zero ow.
+ */
+gb_init(gp, addr)
+       struct grf_softc *gp;
+       u_char *addr;
+{
+       register struct gboxfb *gbp;
+       struct grfinfo *gi = &gp->g_display;
+       u_char *fbp, save;
+       int fboff;
+
+       gbp = (struct gboxfb *) addr;
+       gi->gd_regaddr = (caddr_t) UNIOV(addr);
+       gi->gd_regsize = 0x10000;
+       gi->gd_fbwidth = 1024;          /* XXX */
+       gi->gd_fbheight = 1024;         /* XXX */
+       fboff = (gbp->fbomsb << 8) | gbp->fbolsb;
+       gi->gd_fbaddr = (caddr_t) (*(addr + fboff) << 16);
+       gi->gd_fbsize = gi->gd_fbwidth * gi->gd_fbheight;
+       gi->gd_dwidth = 1024;           /* XXX */
+       gi->gd_dheight = 768;           /* XXX */
+       gi->gd_planes = 0;              /* how do we do this? */
+       /*
+        * The minimal register info here is from the Gatorbox X driver.
+        */
+       fbp = (u_char *) IOV(gi->gd_fbaddr);
+       gbp->write_protect = 0;
+       gbp->interrupt = 4;             /** fb_enable ? **/
+       gbp->rep_rule = 3;              /* GXcopy */
+       gbp->blink1 = 0xff;
+       gbp->blink2 = 0xff;
+
+       gb_microcode(gbp);
+
+       /*
+        * Find out how many colors are available by determining
+        * which planes are installed.  That is, write all ones to
+        * a frame buffer location, see how many ones are read back.
+        */
+       save = *fbp;
+       *fbp = 0xFF;
+       gi->gd_colors = *fbp + 1;
+       *fbp = save;
+       return(1);
+}
+
+/*
+ * Program the 6845.
+ */
+gb_microcode(gbp)
+       register struct gboxfb *gbp;
+{
+       register int i;
+       
+       for (i = 0; i < CRTC_DATA_LENGTH; i++) {
+               gbp->crtc_address = i;
+               gbp->crtc_data = crtc_init_data[i];
+       }
+}
+
+/*
+ * Change the mode of the display.
+ * Right now all we can do is grfon/grfoff.
+ * Return a UNIX error number or 0 for success.
+ */
+gb_mode(gp, cmd)
+       register struct grf_softc *gp;
+{
+       struct gboxfb *gbp;
+       int error = 0;
+
+       gbp = (struct gboxfb *) IOV(gp->g_display.gd_regaddr);
+       switch (cmd) {
+       case GM_GRFON:
+               gbp->sec_interrupt = 1;
+               break;
+       case GM_GRFOFF:
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return(error);
+}
+
+#endif
diff --git a/usr/src/sys/hp300/dev/grf_gbreg.h b/usr/src/sys/hp300/dev/grf_gbreg.h
new file mode 100644 (file)
index 0000000..7449492
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_gbreg.h 1.10 89/08/25$
+ *
+ *     @(#)grf_gbreg.h 7.1 (Berkeley) %G%
+ */
+
+/*
+ * Gatorbox driver regs
+ */
+
+#define TILER_ENABLE           0x80
+#define LINE_MOVER_ENABLE      0x80
+#define UP_LEFT                0x00
+#define DOWN_RIGHT             0x40
+#define MOVE_UP_LEFT           TILER_ENABLE|UP_LEFT
+#define MOVE_DOWN_RIGHT        TILER_ENABLE|DOWN_RIGHT
+
+#define tile_mover_waitbusy(regaddr) \
+       while (((struct gboxfb *)(regaddr))->sec_interrupt & 0x10)
+
+#define line_mover_waitbusy(regaddr) \
+       while ((((struct gboxfb *)(regaddr))->status & 0x80) == 0)
+
+#define gbcm_waitbusy(regaddr) \
+       while (((struct gboxfb *)(regaddr))->cmap_busy != 0xff)
+
+#define        vu_char         volatile u_char
+
+struct gboxfb {
+  u_char       :8;
+  vu_char      reset;                  /* reset register               0x01 */
+  vu_char      sec_interrupt;          /* Secondary interrupt register 0x03 */
+  vu_char      interrupt;              /* interrupt register           0x03 */
+  u_char       :8;
+  vu_char      fbwmsb;                 /* frame buffer width MSB       0x05 */
+  u_char       :8;
+  vu_char      fbwlsb;                 /* frame buffer width MSB       0x07 */
+  u_char       :8;
+  vu_char      fbhmsb;                 /* frame buffer height MSB      0x09 */
+  u_char       :8;
+  vu_char      fbhlsb;                 /* frame buffer height MSB      0x0b */
+  u_char       :8;
+  vu_char      dwmsb;                  /* display width MSB            0x0d */
+  u_char       :8;
+  vu_char      dwlsb;                  /* display width MSB            0x0f */
+  u_char       :8;
+  vu_char      dhmsb;                  /* display height MSB           0x11 */
+  u_char       :8;
+  vu_char      dhlsb;                  /* display height MSB           0x13 */
+  u_char       :8;
+  vu_char      fbid;                   /* Scondary frame buffer id     0x15 */
+  u_char       f1[0x5d-0x15-1];
+  vu_char      fbomsb;                 /* frame buffer offset MSB      0x5d */
+  u_char       :8;
+  vu_char      fbolsb;                 /* frame buffer offset LSB      0x5f */
+  u_char       f2[0x4000-0x5f-1];
+  vu_char      crtc_address;           /* CTR controller address reg 0x4000 */
+  vu_char      status;                 /* Status register            0x4001 */
+  vu_char      crtc_data;              /* CTR controller data reg    0x4002 */
+  u_char       f3[6];
+  vu_char      line_mover_rep_rule;    /* Line move rep rule                */
+  u_char       :8, :8;
+  vu_char      line_mover_width;       /* Line move width                   */
+  u_char       f4[0xff3];
+  vu_char      width;                  /* width in tiles             0x5001 */
+  u_char       :8;
+  vu_char      height;                 /* height in tiles            0x5003 */
+  u_char       f5[3];
+  vu_char      rep_rule;               /* replacement rule           0x5007 */
+  u_char       f6[0x6001-0x5007-1];
+  vu_char      blink1;                 /* blink 1                    0x6001 */
+  u_char       f7[3];
+  vu_char      blink2;                 /* blink 2                    0x6005 */
+  u_char       f8[3];
+  vu_char      write_protect;          /* write protect              0x6009 */
+  u_char       f9[0x6803-0x6009-1];
+  vu_char      cmap_busy;              /* color map busy             0x6803 */
+  u_char       f10[0x68b9-0x6803-1];
+  vu_char      creg_select;            /* color map register select  0x68b8 */
+  u_char       f11[0x68f1-0x68b9-1];
+  vu_char      cmap_write;             /* color map write trigger    0x68f1 */
+  u_char       f12[0x69b3-0x68f1-1];
+  vu_char      cmap_red;               /* red value register         0x69b3 */
+  u_char       :8;
+  vu_char      cmap_grn;               /* green value register       0x69b5 */
+  u_char       :8;
+  vu_char      cmap_blu;               /* blue value register        0x69b6 */
+};
diff --git a/usr/src/sys/hp300/dev/grf_rb.c b/usr/src/sys/hp300/dev/grf_rb.c
new file mode 100644 (file)
index 0000000..f9f89d4
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_rb.c 1.10 89/04/11$
+ *
+ *     @(#)grf_rb.c    7.1 (Berkeley) %G%
+ */
+
+#include "grf.h"
+#if NGRF > 0
+
+/*
+ * Graphics routines for the Renaissance, HP98720 Graphics system.
+ */
+#include "param.h"
+#include "errno.h"
+
+#include "grfioctl.h"
+#include "grfvar.h"
+#include "grf_rbreg.h"
+
+#include "machine/cpu.h"
+
+#ifdef notyet
+static short rb_microcode[] = {
+       0x5efe, 0x8a38, 0x0000, 0x0000, 0x0f00, 0, 0, 0,
+       0x3efe, 0x8a38, 0x0000, 0x7003, 0xf706, 0, 0, 0,
+       0x1efe, 0x8a38, 0x0000, 0x0000, 0x0000, 0, 0, 0,
+       0x3efe, 0x8a38, 0x0000, 0x7003, 0xfc06, 0, 0, 0,
+       0x1efe, 0x8a38, 0x0000, 0x0000, 0x0000, 0, 0, 0,
+       0x3efe, 0x8a38, 0x0004, 0x40f7, 0xa006, 0, 0, 0,
+       0x9efe, 0x8a38, 0x0000, 0x0000, 0x0000, 0, 0, 0,
+       0x1efe, 0x8a38, 0x0000, 0x0000, 0x0000
+};
+#endif
+
+/*
+ * Initialize hardware.
+ * Must point g_display at a grfinfo structure describing the hardware.
+ * Returns 0 if hardware not present, non-zero ow.
+ */
+rb_init(gp, addr)
+       struct grf_softc *gp;
+       u_char *addr;
+{
+       register struct rboxfb *rbp;
+       struct grfinfo *gi = &gp->g_display;
+       int fboff;
+
+       rbp = (struct rboxfb *) addr;
+       gi->gd_regaddr = (caddr_t) UNIOV(addr);
+       gi->gd_regsize = 0x20000;
+       gi->gd_fbwidth = (rbp->fbwmsb << 8) | rbp->fbwlsb;
+       gi->gd_fbheight = (rbp->fbhmsb << 8) | rbp->fbhlsb;
+       fboff = (rbp->fbomsb << 8) | rbp->fbolsb;
+       gi->gd_fbaddr = (caddr_t) (*(addr + fboff) << 16);
+       gi->gd_fbsize = gi->gd_fbwidth * gi->gd_fbheight;
+       gi->gd_dwidth = (rbp->dwmsb << 8) | rbp->dwlsb;
+       gi->gd_dheight = (rbp->dwmsb << 8) | rbp->dwlsb;
+       gi->gd_planes = 0;      /* ?? */
+       gi->gd_colors = 256;
+       return(1);
+}
+
+#ifdef notyet
+/*
+ * Download the microcode to the rbox.
+ */
+rb_download_microcode(regbase)
+     caddr_t regbase;
+{
+       register short *rb_microcode_ptr = rb_microcode;
+       register short *rb_cntlstore_ptr = (short *)((char *)regbase + 0xC000);
+       register int i;
+
+       /*
+        * Reset and halt transform engine
+        */
+       *((char *)regbase + 0x8002) = 0x00a0;
+       *((char *)regbase + 0x8002) = 0x0020;
+       *((char *)regbase + 0x8002) = 0x0080;
+
+       /*
+        * Select the first bank of control store.
+        */
+       *((char *)regbase + 0x8007) = 0x0;
+
+       /*
+        * Write the microcode into the control store address space.
+        */
+       for (i = 0; i < sizeof(rb_microcode) / sizeof(rb_microcode[0]); i++)
+               *rb_cntlstore_ptr++ = *rb_microcode_ptr++;
+
+       /*
+        * Start microcode execution.
+        */
+       *(short *)((char *)regbase + 0x8002) = 0x2000;
+       *(short *)((char *)regbase + 0x8002) = 0x0;
+       
+       /*
+        * wait for renaissance to finish up.
+        */
+       for (i = 0; i < 1000; i++) {
+               if (*((char *)regbase + 0x8012) < 0)
+                       continue;
+       }
+}
+#endif
+
+/*
+ * Change the mode of the display.
+ * Right now all we can do is grfon/grfoff.
+ * Return a UNIX error number or 0 for success.
+ */
+rb_mode(gp, cmd)
+       register struct grf_softc *gp;
+{
+       register struct rboxfb *rbp;
+       int error = 0;
+
+       rbp = (struct rboxfb *) IOV(gp->g_display.gd_regaddr);
+       switch (cmd) {
+       /*
+        * The minimal register info here is from the Renaissance X driver.
+        */
+       case GM_GRFON:
+       case GM_GRFOFF:
+               break;
+       case GM_GRFOVON:
+               rbp->write_enable = 0;
+               rbp->opwen = 0xF;
+               rbp->drive = 0x10;
+               break;
+       case GM_GRFOVOFF:
+               rbp->opwen = 0;
+               rbp->write_enable = 0xffffffff;
+               rbp->drive = 0x01;
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return(error);
+}
+
+#endif
diff --git a/usr/src/sys/hp300/dev/grf_rbreg.h b/usr/src/sys/hp300/dev/grf_rbreg.h
new file mode 100644 (file)
index 0000000..b1b9224
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_rbreg.h 1.8 89/08/25$
+ *
+ *     @(#)grf_rbreg.h 7.1 (Berkeley) %G%
+ */
+
+/*
+ * Map of the Renaissance frame buffer controller chip in memory ...
+ */
+
+#define rb_waitbusy(regaddr) \
+       while (((struct rboxfb *)(regaddr))->wbusy & 0x01) DELAY(100)
+
+#define        CM1RED  ((struct rencm  *)(ip->regbase + 0x6400))
+#define        CM1GRN  ((struct rencm  *)(ip->regbase + 0x6800))
+#define        CM1BLU  ((struct rencm  *)(ip->regbase + 0x6C00))
+#define        CM2RED  ((struct rencm  *)(ip->regbase + 0x7400))
+#define        CM2GRN  ((struct rencm  *)(ip->regbase + 0x7800))
+#define        CM2BLU  ((struct rencm  *)(ip->regbase + 0x7C00))
+
+#define        vu_char         volatile u_char
+#define        vu_short        volatile u_short
+#define        vu_int          volatile u_int
+
+struct rencm {
+       u_char  :8, :8, :8;
+       vu_char value;
+};
+
+struct rboxfb {
+    u_char     filler1[1];
+    vu_char    reset;                  /* reset register               0x01 */
+    vu_char    fb_address;             /* frame buffer address         0x02 */
+    vu_char    interrupt;              /* interrupt register           0x03 */
+    u_char     filler1a;
+    vu_char    fbwmsb;                 /* frame buffer width MSB       0x05 */
+    u_char     filler1b;
+    vu_char    fbwlsb;                 /* frame buffer width MSB       0x07 */
+    u_char     filler1c;
+    vu_char    fbhmsb;                 /* frame buffer height MSB      0x09 */
+    u_char     filler1d;
+    vu_char    fbhlsb;                 /* frame buffer height MSB      0x0b */
+    u_char     filler1e;
+    vu_char    dwmsb;                  /* display width MSB            0x0d */
+    u_char     filler1f;
+    vu_char    dwlsb;                  /* display width MSB            0x0f */
+    u_char     filler1g;
+    vu_char    dhmsb;                  /* display height MSB           0x11 */
+    u_char     filler1h;
+    vu_char    dhlsb;                  /* display height MSB           0x13 */
+    u_char     filler1i;
+    vu_char    fbid;                   /* frame buffer id              0x15 */
+    u_char     filler1j[0x47];
+    vu_char    fbomsb;                 /* frame buffer offset MSB      0x5d */
+    u_char     filler1k;
+    vu_char    fbolsb;                 /* frame buffer offset LSB      0x5f */
+    u_char     filler2[16359];
+    vu_char    wbusy;                  /* window mover is active     0x4047 */
+    u_char      filler3[0x405b - 0x4048];
+    vu_char    scanbusy;               /* scan converteris active    0x405B */
+    u_char      filler3b[0x4083 - 0x405c];
+    vu_char    video_enable;           /* drive vid. refresh bus     0x4083 */
+    u_char     filler4[3];
+    vu_char    display_enable;         /* enable the display         0x4087 */
+    u_char     filler5[8];
+    vu_int     write_enable;           /* write enable register      0x4090 */
+    u_char     filler6[11];
+    vu_char    wmove;                  /* start window mover         0x409f */
+    u_char     filler7[3];
+    vu_char    blink;                  /* blink register             0x40a3 */
+    u_char     filler8[15];
+    vu_char    fold;                   /* fold  register             0x40b3 */
+    vu_int     opwen;                  /* overlay plane write enable 0x40b4 */
+    u_char     filler9[3];
+    vu_char    tmode;                  /* Tile mode size             0x40bb */
+    u_char     filler9a[3];            
+    vu_char    drive;                  /* drive register             0x40bf */
+    u_char     filler10[3];
+    vu_char    vdrive;                 /* vdrive register            0x40c3 */
+    u_char     filler10a[0x40cb-0x40c4];
+    vu_char    zconfig;                /* Z-buffer mode              0x40cb */
+    u_char     filler11a[2];
+    vu_short   tpatt;                  /* Transparency pattern       0x40ce */
+    u_char     filler11b[3];
+    vu_char    dmode;                  /* dither mode                0x40d3 */
+    u_char     filler11c[3];
+    vu_char    en_scan;                /* enable scan board to DTACK 0x40d7 */
+    u_char     filler11d[0x40ef-0x40d8];
+    vu_char    rep_rule;               /* replacement rule           0x40ef */
+    u_char     filler12[2];
+    vu_short   source_x;               /* source x                   0x40f2 */
+    u_char     filler13[2];
+    vu_short   source_y;               /* source y                   0x40f6 */
+    u_char     filler14[2];
+    vu_short   dest_x;                 /* dest x                     0x40fa */
+    u_char     filler15[2];
+    vu_short   dest_y;                 /* dest y                     0x40fe */
+    u_char     filler16[2];
+    vu_short   wwidth;                 /* window width               0x4102 */
+    u_char     filler17[2];
+    vu_short   wheight;                /* window height              0x4106 */
+    u_char     filler18[18];
+    vu_short   patt_x;                 /* pattern x                  0x411a */
+    u_char     filler19[2];
+    vu_short   patt_y;                 /* pattern y                  0x411e */
+    u_char     filler20[0x8012 - 0x4120];
+    vu_short   te_status;              /* transform engine status    0x8012 */
+    u_char     filler21[0x1ffff-0x8014];
+};
diff --git a/usr/src/sys/hp300/dev/grf_tc.c b/usr/src/sys/hp300/dev/grf_tc.c
new file mode 100644 (file)
index 0000000..3a3d14a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_tc.c 1.13 89/08/25$
+ *
+ *     @(#)grf_tc.c    7.1 (Berkeley) %G%
+ */
+
+#include "grf.h"
+#if NGRF > 0
+
+/*
+ * Graphics routines for TOPCAT frame buffer
+ */
+#include "param.h"
+#include "errno.h"
+
+#include "grfioctl.h"
+#include "grfvar.h"
+#include "grf_tcreg.h"
+
+#include "machine/cpu.h"
+
+/*
+ * Initialize hardware.
+ * Must fill in the grfinfo structure in g_softc.
+ * Returns 0 if hardware not present, non-zero ow.
+ */
+tc_init(gp, addr)
+       struct grf_softc *gp;
+       u_char *addr;
+{
+       register struct tcboxfb *tp = (struct tcboxfb *) addr;
+       struct grfinfo *gi = &gp->g_display;
+       volatile u_char *fbp;
+       u_char save;
+       int fboff;
+
+#if defined(HP360) || defined(HP370)
+       extern char grfregs[];
+       if (addr == (u_char *)grfregs)
+               gi->gd_regaddr = (caddr_t) DIOIIBASE;
+       else
+#endif
+       gi->gd_regaddr = (caddr_t) UNIOV(addr);
+       gi->gd_regsize = 0x10000;
+       gi->gd_fbwidth = (tp->fbwmsb << 8) | tp->fbwlsb;
+       gi->gd_fbheight = (tp->fbhmsb << 8) | tp->fbhlsb;
+       fboff = (tp->fbomsb << 8) | tp->fbolsb;
+       gi->gd_fbaddr = (caddr_t) (*(addr + fboff) << 16);
+#if defined(HP360) || defined(HP370)
+       /*
+        * For DIO II space addresses offset is relative to the DIO II space.
+        * XXX: this should apply to all frame buffer types.
+        */
+       if (gi->gd_regaddr >= (caddr_t)DIOIIBASE)
+               gi->gd_fbaddr += (int) gi->gd_regaddr;
+#endif
+       gi->gd_fbsize = gi->gd_fbwidth * gi->gd_fbheight;
+       gi->gd_dwidth = (tp->dwmsb << 8) | tp->dwlsb;
+       gi->gd_dheight = (tp->dhmsb << 8) | tp->dhlsb;
+       gi->gd_planes = tp->num_planes;
+       gi->gd_colors = 1 << gi->gd_planes;
+       if (gi->gd_colors == 1) {
+               fbp = (u_char *) IOV(gi->gd_fbaddr);
+               tp->wen = ~0;
+               tp->prr = 0x3;
+               tp->fben = ~0;
+               save = *fbp;
+               *fbp = 0xFF;
+               gi->gd_colors = *fbp + 1;
+               *fbp = save;
+       }
+       return(1);
+}
+
+/*
+ * Change the mode of the display.
+ * Right now all we can do is grfon/grfoff.
+ * Return a UNIX error number or 0 for success.
+ * Function may not be needed anymore.
+ */
+/*ARGSUSED*/
+tc_mode(gp, cmd)
+       struct grf_softc *gp;
+{
+       int error = 0;
+
+       switch (cmd) {
+       case GM_GRFON:
+       case GM_GRFOFF:
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return(error);
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/grf_tcreg.h b/usr/src/sys/hp300/dev/grf_tcreg.h
new file mode 100644 (file)
index 0000000..c26a467
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: grf_tcreg.h 1.9 89/08/24$
+ *
+ *     @(#)grf_tcreg.h 7.1 (Berkeley) %G%
+ */
+
+#define tccm_waitbusy(regaddr) \
+       while (((struct tcboxfb *)(regaddr))->cmap_busy & 0x04) DELAY(100)
+
+#define tc_waitbusy(regaddr,planes) \
+       while (((struct tcboxfb *)(regaddr))->busy & planes) DELAY(100)
+
+#define        vu_char         volatile u_char
+#define        vu_short        volatile u_short
+
+struct tcboxfb {
+  u_char       :8;
+  vu_char      reset;                  /* reset register               0x01 */
+  vu_char      fb_address;             /* frame buffer address         0x02 */
+  vu_char      interrupt;              /* interrupt register           0x03 */
+  u_char       :8;
+  vu_char      fbwmsb;                 /* frame buffer width MSB       0x05 */
+  u_char       :8;
+  vu_char      fbwlsb;                 /* frame buffer width MSB       0x07 */
+  u_char       :8;
+  vu_char      fbhmsb;                 /* frame buffer height MSB      0x09 */
+  u_char       :8;
+  vu_char      fbhlsb;                 /* frame buffer height MSB      0x0b */
+  u_char       :8;
+  vu_char      dwmsb;                  /* display width MSB            0x0d */
+  u_char       :8;
+  vu_char      dwlsb;                  /* display width MSB            0x0f */
+  u_char       :8;
+  vu_char      dhmsb;                  /* display height MSB           0x11 */
+  u_char       :8;
+  vu_char      dhlsb;                  /* display height MSB           0x13 */
+  u_char       :8;
+  vu_char      fbid;                   /* Scondary frame buffer id     0x15 */
+  u_char       :8;
+  vu_char      bits;                   /* square(0)/double-high(1)     0x17 */
+  u_char       f1[0x5b-0x17-1];
+  vu_char      num_planes;             /* number of color planes       0x5b */
+  u_char       :8;
+  vu_char      fbomsb;                 /* frame buffer offset MSB      0x5d */
+  u_char       :8;
+  vu_char      fbolsb;                 /* frame buffer offset LSB      0x5f */
+  u_char       f2[0x4040-0x5f-1];
+  vu_char      vblank;                 /* vertical blanking          0x4040 */
+  u_char       :8,:8,:8;
+  vu_char      busy;                   /* window move active         0x4044 */
+  u_char       :8,:8,:8;
+  vu_char      vtrace_request;         /* vert retrace intr request  0x4048 */
+  u_char       :8,:8,:8;
+  vu_char      move_request;           /* window move intr request   0x404C */
+  u_char       f3[0x4080-0x404c-1];
+  vu_char      nblank;                 /* display enable planes      0x4080 */
+  u_char       f4[0x4088-0x4080-1];
+  vu_char      wen;                    /* write enable plane         0x4088 */
+  u_char       f5[0x408c-0x4088-1];
+  vu_char      ren;                    /* read enable plane          0x408c */
+  u_char       f6[0x4090-0x408c-1];
+  vu_char      fben;                   /* frame buffer write enable  0x4090 */
+  u_char       f7[0x409c-0x4090-1];
+  vu_char      wmove;                  /* start window move          0x409c */
+  u_char       f8[0x40a0-0x409c-1];
+  vu_char      blink;                  /* enable blink planes        0x40a0 */
+  u_char       f9[0x40a8-0x40a0-1];
+  vu_char      altframe;               /* enable alternate frame     0x40a8 */
+  u_char       f10[0x40ac-0x40a8-1];
+  vu_char      curon;                  /* cursor control register    0x40ac */
+  u_char       f11[0x40ea-0x40ac-1];
+  vu_char      prr;                    /* pixel replacement rule     0x40ea */
+  u_char       f12[0x40ef-0x40ea-1];
+  vu_char      wmrr;                   /* move replacement rule      0x40ef */
+  u_char       f13[0x40f2-0x40ef-1];
+  vu_short     source_x;               /* source x pixel #           0x40f2 */
+  u_char       f14[0x40f6-0x40f2-2];
+  vu_short     source_y;               /* source y pixel #           0x40f6 */
+  u_char       f15[0x40fa-0x40f6-2];
+  vu_short     dest_x;                 /* dest x pixel #             0x40fa */
+  u_char       f16[0x40fe-0x40fa-2];
+  vu_short     dest_y;                 /* dest y pixel #             0x40fe */
+  u_char       f17[0x4102-0x40fe-2];
+  vu_short     wwidth;                 /* block mover pixel width    0x4102 */
+  u_char       f18[0x4106-0x4102-2];
+  vu_short     wheight;                /* block mover pixel height   0x4106 */
+  u_char       f19[0x6002-0x4106-2];
+  vu_short     cmap_busy;              /* Color Ram busy             0x6002 */
+  u_char       f20[0x60b2-0x6002-2];
+  vu_short     rdata;                  /* color map red data         0x60b2 */
+  vu_short     gdata;                  /* color map green data       0x60b4 */
+  vu_short     bdata;                  /* color map blue data        0x60b6 */
+  vu_short     cindex;                 /* color map index            0x60b8 */
+  vu_short     plane_mask;             /* plane mask select          0x60ba */
+  u_char       f21[0x60f0-0x60ba-2];
+  vu_short     strobe;                 /* color map trigger          0x60f0 */
+};
+
diff --git a/usr/src/sys/hp300/dev/hpib.c b/usr/src/sys/hp300/dev/hpib.c
new file mode 100644 (file)
index 0000000..ca81d42
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)hpib.c      7.1 (Berkeley) %G%
+ */
+
+/*
+ * HPIB driver
+ */
+#include "hpib.h"
+#if NHPIB > 0
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "device.h"
+#include "hpibvar.h"
+#include "dmavar.h"
+
+#include "machine/cpu.h"
+#include "machine/isr.h"
+
+int    internalhpib = IOV(0x478000);
+
+int    hpibinit(), hpibstart(), hpibgo(), hpibintr(), hpibdone();
+struct driver hpibdriver = {
+       hpibinit, "hpib", hpibstart, hpibgo, hpibintr, hpibdone,
+};
+
+struct hpib_softc hpib_softc[NHPIB];
+struct isr hpib_isr[NHPIB];
+int    nhpibppoll(), fhpibppoll();
+
+int    hpibtimeout = 100000;   /* # of status tests before we give up */
+int    hpibidtimeout = 20000;  /* # of status tests for hpibid() calls */
+
+hpibinit(hc)
+       register struct hp_ctlr *hc;
+{
+       register struct hpib_softc *hs = &hpib_softc[hc->hp_unit];
+       
+       if (!nhpibtype(hc) && !fhpibtype(hc))
+               return(0);
+       hs->sc_hc = hc;
+       hs->sc_dq.dq_unit = hc->hp_unit;
+       hs->sc_dq.dq_driver = &hpibdriver;
+       hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
+       hpib_isr[hc->hp_unit].isr_intr = hpibintr;
+       hpib_isr[hc->hp_unit].isr_ipl = hc->hp_ipl;
+       hpib_isr[hc->hp_unit].isr_arg = hc->hp_unit;
+       isrlink(&hpib_isr[hc->hp_unit]);
+       hpibreset(hc->hp_unit);
+       return(1);
+}
+
+hpibreset(unit)
+       register int unit;
+{
+       if (hpib_softc[unit].sc_type == HPIBC)
+               fhpibreset(unit);
+       else
+               nhpibreset(unit);
+}
+
+hpibreq(dq)
+       register struct devqueue *dq;
+{
+       register struct devqueue *hq;
+
+       hq = &hpib_softc[dq->dq_ctlr].sc_sq;
+       insque(dq, hq->dq_back);
+       if (dq->dq_back == hq)
+               return(1);
+       return(0);
+}
+
+hpibfree(dq)
+       register struct devqueue *dq;
+{
+       register struct devqueue *hq;
+
+       hq = &hpib_softc[dq->dq_ctlr].sc_sq;
+       remque(dq);
+       if ((dq = hq->dq_forw) != hq)
+               (dq->dq_driver->d_start)(dq->dq_unit);
+}
+
+hpibid(unit, slave)
+{
+       short id;
+       int ohpibtimeout;
+
+       /*
+        * XXX: shorten timeout value (so autoconfig doesn't take forever)
+        */
+       ohpibtimeout = hpibtimeout;
+       hpibtimeout = hpibidtimeout;
+       if (hpibrecv(unit, 31, slave, &id, 2) != 2)
+               id = 0;
+       hpibtimeout = ohpibtimeout;
+       return(id);
+}
+
+hpibsend(unit, slave, sec, addr, cnt)
+       register int unit;
+{
+       if (hpib_softc[unit].sc_type == HPIBC)
+               return(fhpibsend(unit, slave, sec, addr, cnt));
+       else
+               return(nhpibsend(unit, slave, sec, addr, cnt));
+}
+
+hpibrecv(unit, slave, sec, addr, cnt)
+       register int unit;
+{
+       if (hpib_softc[unit].sc_type == HPIBC)
+               return(fhpibrecv(unit, slave, sec, addr, cnt));
+       else
+               return(nhpibrecv(unit, slave, sec, addr, cnt));
+}
+
+hpibpptest(unit, slave)
+       register int unit;
+{
+       int (*ppoll)();
+
+       ppoll = (hpib_softc[unit].sc_type == HPIBC) ? fhpibppoll : nhpibppoll;
+       return((*ppoll)(unit) & (0x80 >> slave));
+}
+
+hpibawait(unit)
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+
+       hs->sc_flags |= HPIBF_PPOLL;
+       if (hs->sc_type == HPIBC)
+               fhpibppwatch(unit);
+       else
+               nhpibppwatch(unit);
+}
+
+hpibswait(unit, slave)
+       register int unit;
+{
+       register int timo = hpibtimeout;
+       register int mask, (*ppoll)();
+
+       ppoll = (hpib_softc[unit].sc_type == HPIBC) ? fhpibppoll : nhpibppoll;
+       mask = 0x80 >> slave;
+       while (((ppoll)(unit) & mask) == 0)
+               if (--timo == 0) {
+                       printf("hpib%d: swait timeout\n", unit);
+                       return(-1);
+               }
+       return(0);
+}
+
+hpibustart(unit)
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+
+       if (hs->sc_type == HPIBA)
+               hs->sc_dq.dq_ctlr = DMA0;
+       else
+               hs->sc_dq.dq_ctlr = DMA0 | DMA1;
+       if (dmareq(&hs->sc_dq))
+               return(1);
+       return(0);
+}
+
+hpibstart(unit)
+{
+       register struct devqueue *dq;
+       
+       dq = hpib_softc[unit].sc_sq.dq_forw;
+       (dq->dq_driver->d_go)(dq->dq_unit);
+}
+
+hpibgo(unit, slave, sec, addr, count, rw)
+       register int unit;
+{
+       if (hpib_softc[unit].sc_type == HPIBC)
+               fhpibgo(unit, slave, sec, addr, count, rw);
+       else
+               nhpibgo(unit, slave, sec, addr, count, rw);
+}
+
+hpibdone(unit)
+       register int unit;
+{
+       if (hpib_softc[unit].sc_type == HPIBC)
+               fhpibdone(unit);
+       else
+               nhpibdone(unit);
+}
+
+hpibintr(unit)
+       register int unit;
+{
+       int found;
+
+       if (hpib_softc[unit].sc_type == HPIBC)
+               found = fhpibintr(unit);
+       else
+               found = nhpibintr(unit);
+       return(found);
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/hpibvar.h b/usr/src/sys/hp300/dev/hpibvar.h
new file mode 100644 (file)
index 0000000..e657351
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)hpibvar.h   7.1 (Berkeley) %G%
+ */
+
+#define        HPIB_IPL(x)     ((((x) >> 4) & 0x3) + 3)
+
+#define        HPIBA           32
+#define        HPIBB           1
+#define        HPIBC           8
+#define        HPIBA_BA        21
+#define        HPIBC_BA        30
+#define        HPIBA_IPL       3
+
+#define        CSA_BA          0x1F
+
+#define        IDS_WDMA        0x04
+#define        IDS_WRITE       0x08
+#define        IDS_IR          0x40
+#define        IDS_IE          0x80
+#define        IDS_DMA(x)      (1 << (x))
+
+#define        C_DCL           0x14
+#define        C_LAG           0x20
+#define        C_UNL           0x3f
+#define        C_TAG           0x40
+#define        C_UNA           0x5e
+#define        C_UNT           0x5f
+#define        C_SCG           0x60
+
+struct hpib_softc {
+       struct  hp_ctlr *sc_hc;
+       int     sc_flags;
+       struct  devqueue sc_dq;
+       struct  devqueue sc_sq;
+       int     sc_ba;
+       int     sc_type;
+       char    *sc_addr;
+       int     sc_count;
+       int     sc_curcnt;
+};
+
+/* sc_flags */
+#define        HPIBF_IO        0x1
+#define        HPIBF_DONE      0x2
+#define        HPIBF_PPOLL     0x4
+#define        HPIBF_READ      0x8
+#define        HPIBF_DMA16     0x8000
+
+#ifdef KERNEL
+extern struct hpib_softc hpib_softc[];
+extern int internalhpib;
+#endif
diff --git a/usr/src/sys/hp300/dev/if_le.c b/usr/src/sys/hp300/dev/if_le.c
new file mode 100644 (file)
index 0000000..379ad1c
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)if_le.c     7.1 (Berkeley) %G%
+ */
+
+#include "le.h"
+#if NLE > 0
+
+/*
+ * AMD 7990 LANCE
+ *
+ * This driver will generate and accept tailer encapsulated packets even
+ * though it buys us nothing.  The motivation was to avoid incompatibilities
+ * with VAXen, SUNs, and others that handle and benefit from them.
+ * This reasoning is dubious.
+ */
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "syslog.h"
+#include "ioctl.h"
+#include "errno.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+
+#ifdef INET
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#include "../netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "../netns/ns.h"
+#include "../netns/ns_if.h"
+#endif
+
+#ifdef RMP
+#include "../netrmp/rmp.h"
+#include "../netrmp/rmp_var.h"
+#endif
+
+#include "machine/cpu.h"
+#include "machine/isr.h"
+#include "machine/mtpr.h"
+#include "device.h"
+#include "if_lereg.h"
+
+/* offsets for:           ID,   REGS,    MEM,  NVRAM */
+int    lestd[] = { 0, 0x4000, 0x8000, 0xC008 };
+
+int    leattach();
+struct driver ledriver = {
+       leattach, "le",
+};
+
+struct isr le_isr[NLE];
+int    ledebug = 0;            /* console error messages */
+
+int    leintr(), leinit(), leioctl(), lestart(), ether_output();
+struct mbuf *leget();
+extern struct ifnet loif;
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * le_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ */
+struct le_softc {
+       struct  arpcom sc_ac;   /* common Ethernet structures */
+#define        sc_if   sc_ac.ac_if     /* network-visible interface */
+#define        sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */
+       struct  lereg0 *sc_r0;  /* DIO registers */
+       struct  lereg1 *sc_r1;  /* LANCE registers */
+       struct  lereg2 *sc_r2;  /* dual-port RAM */
+       int     sc_rmd;         /* predicted next rmd to process */
+       int     sc_runt;
+       int     sc_jab;
+       int     sc_merr;
+       int     sc_babl;
+       int     sc_cerr;
+       int     sc_miss;
+       int     sc_xint;
+       int     sc_xown;
+       int     sc_uflo;
+       int     sc_rxlen;
+       int     sc_rxoff;
+       int     sc_txoff;
+       int     sc_busy;
+} le_softc[NLE];
+
+/* access LANCE registers */
+#define        LERDWR(cntl, src, dst) \
+       do { \
+               (dst) = (src); \
+       } while (((cntl)->ler0_status & LE_ACK) == 0);
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+leattach(hd)
+       struct hp_device *hd;
+{
+       register struct lereg0 *ler0;
+       register struct lereg2 *ler2;
+       struct lereg2 *lemem = 0;
+       struct le_softc *le = &le_softc[hd->hp_unit];
+       struct ifnet *ifp = &le->sc_if;
+       char *cp;
+       int i;
+
+       ler0 = le->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr);
+       le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr);
+       ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr);
+       if (ler0->ler0_id != LEID)
+               return(0);
+       le_isr[hd->hp_unit].isr_intr = leintr;
+       hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status);
+       le_isr[hd->hp_unit].isr_arg = hd->hp_unit;
+       ler0->ler0_id = 0xFF;
+       DELAY(100);
+
+       /*
+        * Read the ethernet address off the board, one nibble at a time.
+        */
+       cp = (char *)(lestd[3] + (int)hd->hp_addr);
+       for (i = 0; i < sizeof(le->sc_addr); i++) {
+               le->sc_addr[i] = (*++cp & 0xF) << 4;
+               cp++;
+               le->sc_addr[i] |= *++cp & 0xF;
+               cp++;
+       }
+       printf("le%d: hardware address %s\n", hd->hp_unit,
+               ether_sprintf(le->sc_addr));
+
+       /*
+        * Setup for transmit/receive
+        */
+       ler2->ler2_mode = LE_MODE;
+       ler2->ler2_padr[0] = le->sc_addr[1];
+       ler2->ler2_padr[1] = le->sc_addr[0];
+       ler2->ler2_padr[2] = le->sc_addr[3];
+       ler2->ler2_padr[3] = le->sc_addr[2];
+       ler2->ler2_padr[4] = le->sc_addr[5];
+       ler2->ler2_padr[5] = le->sc_addr[4];
+#ifdef RMP
+       /*
+        * Set up logical addr filter to accept multicast 9:0:9:0:0:4
+        * This should be an ioctl() to the driver.  (XXX)
+        */
+       ler2->ler2_ladrf0 = 0x00100000;
+       ler2->ler2_ladrf1 = 0x0;
+#else
+       ler2->ler2_ladrf0 = 0;
+       ler2->ler2_ladrf1 = 0;
+#endif
+       ler2->ler2_rlen = LE_RLEN;
+       ler2->ler2_rdra = (int)lemem->ler2_rmd;
+       ler2->ler2_tlen = LE_TLEN;
+       ler2->ler2_tdra = (int)lemem->ler2_tmd;
+       isrlink(&le_isr[hd->hp_unit]);
+       ler0->ler0_status = LE_IE;
+
+       ifp->if_unit = hd->hp_unit;
+       ifp->if_name = "le";
+       ifp->if_mtu = ETHERMTU;
+       ifp->if_init = leinit;
+       ifp->if_ioctl = leioctl;
+       ifp->if_output = ether_output;
+       ifp->if_start = lestart;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+       if_attach(ifp);
+       return (1);
+}
+
+ledrinit(ler2)
+       register struct lereg2 *ler2;
+{
+       register struct lereg2 *lemem = 0;
+       register int i;
+
+       for (i = 0; i < LERBUF; i++) {
+               ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i];
+               ler2->ler2_rmd[i].rmd1 = LE_OWN;
+               ler2->ler2_rmd[i].rmd2 = -LEMTU;
+               ler2->ler2_rmd[i].rmd3 = 0;
+       }
+       for (i = 0; i < LETBUF; i++) {
+               ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i];
+               ler2->ler2_tmd[i].tmd1 = 0;
+               ler2->ler2_tmd[i].tmd2 = 0;
+               ler2->ler2_tmd[i].tmd3 = 0;
+       }
+}
+
+lereset(unit)
+       register int unit;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register struct lereg0 *ler0 = le->sc_r0;
+       register struct lereg1 *ler1 = le->sc_r1;
+       register struct lereg2 *lemem = 0;
+       register int timo = 100000;
+       register int stat;
+
+#ifdef lint
+       stat = unit;
+#endif
+       LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
+       LERDWR(ler0, LE_STOP, ler1->ler1_rdp);
+       ledrinit(le->sc_r2);
+       le->sc_rmd = 0;
+       LERDWR(ler0, LE_CSR1, ler1->ler1_rap);
+       LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp);
+       LERDWR(ler0, LE_CSR2, ler1->ler1_rap);
+       LERDWR(ler0, 0, ler1->ler1_rdp);
+       LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
+       LERDWR(ler0, LE_INIT, ler1->ler1_rdp);
+       do {
+               if (--timo == 0) {
+                       printf("le%d: init timeout, stat = 0x%x\n",
+                              unit, stat);
+                       break;
+               }
+               LERDWR(ler0, ler1->ler1_rdp, stat);
+       } while ((stat & LE_IDON) == 0);
+       LERDWR(ler0, LE_STOP, ler1->ler1_rdp);
+       LERDWR(ler0, LE_CSR3, ler1->ler1_rap);
+       LERDWR(ler0, LE_BSWP, ler1->ler1_rdp);
+       LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
+       LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp);
+       le->sc_if.if_flags &= ~IFF_OACTIVE;
+}
+
+/*
+ * Initialization of interface
+ */
+leinit(unit)
+       int unit;
+{
+       struct le_softc *le = &le_softc[unit];
+       register struct ifnet *ifp = &le->sc_if;
+       int s;
+
+       /* not yet, if address still unknown */
+       if (ifp->if_addrlist == (struct ifaddr *)0)
+               return;
+       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+               s = splimp();
+               ifp->if_flags |= IFF_RUNNING;
+               lereset(unit);
+               (void) lestart(ifp);
+               splx(s);
+       }
+}
+
+/*
+ * Start output on interface.  Get another datagram to send
+ * off of the interface queue, and copy it to the interface
+ * before starting the output.
+ */
+lestart(ifp)
+       struct ifnet *ifp;
+{
+       register struct le_softc *le = &le_softc[ifp->if_unit];
+       register struct letmd *tmd;
+       register struct mbuf *m;
+       int len;
+
+       if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
+               return (0);
+       IF_DEQUEUE(&le->sc_if.if_snd, m);
+       if (m == 0)
+               return (0);
+       len = leput(le->sc_r2->ler2_tbuf[0], m);
+       tmd = le->sc_r2->ler2_tmd;
+       tmd->tmd3 = 0;
+       tmd->tmd2 = -len;
+       tmd->tmd1 = LE_OWN | LE_STP | LE_ENP;
+       le->sc_if.if_flags |= IFF_OACTIVE;
+       return (0);
+}
+
+leintr(unit)
+       register int unit;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register struct lereg0 *ler0 = le->sc_r0;
+       register struct lereg1 *ler1;
+       register int stat;
+
+       if ((ler0->ler0_status & LE_IR) == 0)
+               return(0);
+       if (ler0->ler0_status & LE_JAB) {
+               le->sc_jab++;
+               lereset(unit);
+               return(1);
+       }
+       ler1 = le->sc_r1;
+       LERDWR(ler0, ler1->ler1_rdp, stat);
+       if (stat & LE_SERR) {
+               leerror(unit, stat);
+               if (stat & LE_MERR) {
+                       le->sc_merr++;
+                       lereset(unit);
+                       return(1);
+               }
+               if (stat & LE_BABL)
+                       le->sc_babl++;
+               if (stat & LE_CERR)
+                       le->sc_cerr++;
+               if (stat & LE_MISS)
+                       le->sc_miss++;
+               LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
+       }
+       if ((stat & LE_RXON) == 0) {
+               le->sc_rxoff++;
+               lereset(unit);
+               return(1);
+       }
+       if ((stat & LE_TXON) == 0) {
+               le->sc_txoff++;
+               lereset(unit);
+               return(1);
+       }
+       if (stat & LE_RINT) {
+               /* interrupt is cleared in lerint */
+               lerint(unit);
+       }
+       if (stat & LE_TINT) {
+               LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp);
+               lexint(unit);
+       }
+       return(1);
+}
+
+/*
+ * Ethernet interface transmitter interrupt.
+ * Start another output if more data to send.
+ */
+lexint(unit)
+       register int unit;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register struct letmd *tmd = le->sc_r2->ler2_tmd;
+
+       if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
+               le->sc_xint++;
+               return;
+       }
+       if (tmd->tmd1 & LE_OWN) {
+               le->sc_xown++;
+               return;
+       }
+       if (tmd->tmd1 & LE_ERR) {
+err:
+               lexerror(unit);
+               le->sc_if.if_oerrors++;
+               if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
+                       le->sc_uflo++;
+                       lereset(unit);
+               }
+               else if (tmd->tmd3 & LE_LCOL)
+                       le->sc_if.if_collisions++;
+               else if (tmd->tmd3 & LE_RTRY)
+                       le->sc_if.if_collisions += 16;
+       }
+       else if (tmd->tmd3 & LE_TBUFF)
+               /* XXX documentation says BUFF not included in ERR */
+               goto err;
+       else if (tmd->tmd1 & LE_ONE)
+               le->sc_if.if_collisions++;
+       else if (tmd->tmd1 & LE_MORE)
+               /* what is the real number? */
+               le->sc_if.if_collisions += 2;
+       else
+               le->sc_if.if_opackets++;
+       le->sc_if.if_flags &= ~IFF_OACTIVE;
+       (void) lestart(&le->sc_if);
+}
+
+#define        LENEXTRMP \
+       if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
+
+/*
+ * Ethernet interface receiver interrupt.
+ * If input error just drop packet.
+ * Decapsulate packet based on type and pass to type specific
+ * higher-level input routine.
+ */
+lerint(unit)
+       int unit;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register int bix = le->sc_rmd;
+       register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
+
+       /*
+        * Out of sync with hardware, should never happen?
+        */
+       if (rmd->rmd1 & LE_OWN) {
+               LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
+               return;
+       }
+
+       /*
+        * Process all buffers with valid data
+        */
+       while ((rmd->rmd1 & LE_OWN) == 0) {
+               int len = rmd->rmd3;
+
+               /* Clear interrupt to avoid race condition */
+               LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
+
+               if (rmd->rmd1 & LE_ERR) {
+                       le->sc_rmd = bix;
+                       lererror(unit, "bad packet");
+                       le->sc_if.if_ierrors++;
+               } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
+                       /*
+                        * Find the end of the packet so we can see how long
+                        * it was.  We still throw it away.
+                        */
+                       do {
+                               LERDWR(le->sc_r0, LE_RINT|LE_INEA,
+                                      le->sc_r1->ler1_rdp);
+                               rmd->rmd3 = 0;
+                               rmd->rmd1 = LE_OWN;
+                               LENEXTRMP;
+                       } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
+                       le->sc_rmd = bix;
+                       lererror(unit, "chained buffer");
+                       le->sc_rxlen++;
+                       /*
+                        * If search terminated without successful completion
+                        * we reset the hardware (conservative).
+                        */
+                       if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
+                           LE_ENP) {
+                               lereset(unit);
+                               return;
+                       }
+               } else
+                       leread(unit, le->sc_r2->ler2_rbuf[bix], len);
+               rmd->rmd3 = 0;
+               rmd->rmd1 = LE_OWN;
+               LENEXTRMP;
+       }
+       le->sc_rmd = bix;
+}
+
+leread(unit, buf, len)
+       int unit;
+       char *buf;
+       int len;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register struct ether_header *et;
+       struct mbuf *m;
+       int off, resid;
+
+       le->sc_if.if_ipackets++;
+       et = (struct ether_header *)buf;
+       et->ether_type = ntohs((u_short)et->ether_type);
+       /* adjust input length to account for header and CRC */
+       len = len - sizeof(struct ether_header) - 4;
+
+#ifdef RMP
+       /*  (XXX)
+        *
+        *  If Ethernet Type field is < MaxPacketSize, we probably have
+        *  a IEEE802 packet here.  Make sure that the size is at least
+        *  that of the HP LLC.  Also do sanity checks on length of LLC
+        *  (old Ethernet Type field) and packet length.
+        *
+        *  Provided the above checks succeed, change `len' to reflect
+        *  the length of the LLC (i.e. et->ether_type) and change the
+        *  type field to ETHERTYPE_IEEE so we can switch() on it later.
+        *  Yes, this is a hack and will eventually be done "right".
+        */
+       if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) &&
+           len >= et->ether_type && len >= IEEE802LEN_MIN) {
+               len = et->ether_type;
+               et->ether_type = ETHERTYPE_IEEE;        /* hack! */
+       }
+#endif
+
+#define        ledataaddr(et, off, type)       ((type)(((caddr_t)((et)+1)+(off))))
+       if (et->ether_type >= ETHERTYPE_TRAIL &&
+           et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+               off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
+               if (off >= ETHERMTU)
+                       return;         /* sanity */
+               et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
+               resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
+               if (off + resid > len)
+                       return;         /* sanity */
+               len = off + resid;
+       } else
+               off = 0;
+
+       if (len <= 0) {
+               if (ledebug)
+                       log(LOG_WARNING,
+                           "le%d: ierror(runt packet): from %s: len=%d\n",
+                           unit, ether_sprintf(et->ether_shost), len);
+               le->sc_runt++;
+               le->sc_if.if_ierrors++;
+               return;
+       }
+
+       /*
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; leget will then force this header
+        * information to be at the front, but we still have to drop
+        * the type and length which are at the front of any trailer data.
+        */
+       m = leget(buf, len, off, &le->sc_if);
+       if (m == 0)
+               return;
+#ifdef RMP
+       /*
+        * (XXX)
+        * This needs to be integrated with the ISO stuff in ether_input()
+        */
+       if (et->ether_type == ETHERTYPE_IEEE) {
+               /*
+                *  Snag the Logical Link Control header (IEEE 802.2).
+                */
+               struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc);
+
+               /*
+                *  If the DSAP (and HP's extended DXSAP) indicate this
+                *  is an RMP packet, hand it to the raw input routine.
+                */
+               if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
+                       static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
+                       static struct sockaddr rmp_src = {AF_RMP};
+                       static struct sockaddr rmp_dst = {AF_RMP};
+
+                       bcopy(et->ether_shost, rmp_src.sa_data,
+                             sizeof(et->ether_shost));
+                       bcopy(et->ether_dhost, rmp_dst.sa_data,
+                             sizeof(et->ether_dhost));
+
+                       raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
+                       return;
+               }
+       }
+#endif
+       ether_input(&le->sc_if, et, m);
+}
+
+/*
+ * Routine to copy from mbuf chain to transmit
+ * buffer in board local memory.
+ */
+leput(lebuf, m)
+       register char *lebuf;
+       register struct mbuf *m;
+{
+       register struct mbuf *mp;
+       register int len, tlen = 0;
+
+       for (mp = m; mp; mp = mp->m_next) {
+               len = mp->m_len;
+               if (len == 0)
+                       continue;
+               tlen += len;
+               bcopy(mtod(mp, char *), lebuf, len);
+               lebuf += len;
+       }
+       m_freem(m);
+       if (tlen < LEMINSIZE) {
+               bzero(lebuf, LEMINSIZE - tlen);
+               tlen = LEMINSIZE;
+       }
+       return(tlen);
+}
+
+/*
+ * Routine to copy from board local memory into mbufs.
+ */
+struct mbuf *
+leget(lebuf, totlen, off0, ifp)
+       char *lebuf;
+       int totlen, off0;
+       struct ifnet *ifp;
+{
+       register struct mbuf *m;
+       struct mbuf *top = 0, **mp = &top;
+       register int off = off0, len;
+       register char *cp;
+       char *epkt;
+
+       lebuf += sizeof (struct ether_header);
+       cp = lebuf;
+       epkt = cp + totlen;
+       if (off) {
+               cp += off + 2 * sizeof(u_short);
+               totlen -= 2 * sizeof(u_short);
+       }
+
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m == 0)
+               return (0);
+       m->m_pkthdr.rcvif = ifp;
+       m->m_pkthdr.len = totlen;
+       m->m_len = MHLEN;
+
+       while (totlen > 0) {
+               if (top) {
+                       MGET(m, M_DONTWAIT, MT_DATA);
+                       if (m == 0) {
+                               m_freem(top);
+                               return (0);
+                       }
+                       m->m_len = MLEN;
+               }
+               len = min(totlen, epkt - cp);
+               if (len >= MINCLSIZE) {
+                       MCLGET(m, M_DONTWAIT);
+                       if (m->m_flags & M_EXT)
+                               m->m_len = len = min(len, MCLBYTES);
+                       else
+                               len = m->m_len;
+               } else {
+                       /*
+                        * Place initial small packet/header at end of mbuf.
+                        */
+                       if (len < m->m_len) {
+                               if (top == 0 && len + max_linkhdr <= m->m_len)
+                                       m->m_data += max_linkhdr;
+                               m->m_len = len;
+                       } else
+                               len = m->m_len;
+               }
+               bcopy(cp, mtod(m, caddr_t), (unsigned)len);
+               cp += len;
+               *mp = m;
+               mp = &m->m_next;
+               totlen -= len;
+               if (cp == epkt)
+                       cp = lebuf;
+       }
+       return (top);
+}
+
+/*
+ * Process an ioctl request.
+ */
+leioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       register struct ifaddr *ifa = (struct ifaddr *)data;
+       struct le_softc *le = &le_softc[ifp->if_unit];
+       struct lereg1 *ler1 = le->sc_r1;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       leinit(ifp->if_unit);   /* before arpwhohas */
+                       ((struct arpcom *)ifp)->ac_ipaddr =
+                               IA_SIN(ifa)->sin_addr;
+                       arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+                       break;
+#endif
+#ifdef NS
+               case AF_NS:
+                   {
+                       register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+                       if (ns_nullhost(*ina))
+                               ina->x_host = *(union ns_host *)(le->sc_addr);
+                       else {
+                               /* 
+                                * The manual says we can't change the address 
+                                * while the receiver is armed,
+                                * so reset everything
+                                */
+                               ifp->if_flags &= ~IFF_RUNNING; 
+                               bcopy((caddr_t)ina->x_host.c_host,
+                                   (caddr_t)le->sc_addr, sizeof(le->sc_addr));
+                       }
+                       leinit(ifp->if_unit); /* does le_setaddr() */
+                       break;
+                   }
+#endif
+               default:
+                       leinit(ifp->if_unit);
+                       break;
+               }
+               break;
+
+       case SIOCSIFFLAGS:
+               if ((ifp->if_flags & IFF_UP) == 0 &&
+                   ifp->if_flags & IFF_RUNNING) {
+                       LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp);
+                       ifp->if_flags &= ~IFF_RUNNING;
+               } else if (ifp->if_flags & IFF_UP &&
+                   (ifp->if_flags & IFF_RUNNING) == 0)
+                       leinit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+leerror(unit, stat)
+       int unit;
+       int stat;
+{
+       if (!ledebug)
+               return;
+
+       /*
+        * Not all transceivers implement heartbeat
+        * so we only log CERR once.
+        */
+       if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
+               return;
+       log(LOG_WARNING,
+           "le%d: error: stat=%b\n", unit,
+           stat,
+           "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
+}
+
+lererror(unit, msg)
+       int unit;
+       char *msg;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register struct lermd *rmd;
+       int len;
+
+       if (!ledebug)
+               return;
+
+       rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
+       len = rmd->rmd3;
+       log(LOG_WARNING,
+           "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
+           unit, msg,
+           len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown",
+           le->sc_rmd, len,
+           rmd->rmd1,
+           "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
+}
+
+lexerror(unit)
+       int unit;
+{
+       register struct le_softc *le = &le_softc[unit];
+       register struct letmd *tmd;
+       int len;
+
+       if (!ledebug)
+               return;
+
+       tmd = le->sc_r2->ler2_tmd;
+       len = -tmd->tmd2;
+       log(LOG_WARNING,
+           "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
+           unit,
+           len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown",
+           0, len,
+           tmd->tmd1,
+           "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
+           tmd->tmd3,
+           "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/if_lereg.h b/usr/src/sys/hp300/dev/if_lereg.h
new file mode 100644 (file)
index 0000000..a89d4ad
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)if_lereg.h  7.1 (Berkeley) %G%
+ */
+
+#define        LEID            21
+
+#define        LEMTU           1518
+#define        LEMINSIZE       60      /* should be 64 if mode DTCR is set */
+#define        LERBUF          8
+#define        LERBUFLOG2      3
+#define        LE_RLEN         (LERBUFLOG2 << 13)
+#define        LETBUF          1
+#define        LETBUFLOG2      0
+#define        LE_TLEN         (LETBUFLOG2 << 13)
+
+#define vu_char                volatile u_char
+
+/*
+ * LANCE registers.
+ */
+struct lereg0 {
+       u_char  ler0_pad0;
+       vu_char ler0_id;        /* ID */
+       u_char  ler0_pad1;
+       vu_char ler0_status;    /* interrupt enable/status */
+};
+
+struct lereg1 {
+       u_short ler1_rdp;       /* data port */
+       u_short ler1_rap;       /* register select port */
+};
+
+/*
+ * Overlayed on 16K dual-port RAM.
+ * Current size is 13,758 bytes with 8 x 1518 receive buffers and
+ * 1 x 1518 transmit buffer.
+ */
+struct lereg2 {
+       /* init block */
+       u_short ler2_mode;              /* +0x0000 */
+       u_char  ler2_padr[6];           /* +0x0002 */
+       u_long  ler2_ladrf0;            /* +0x0008 */
+       u_long  ler2_ladrf1;            /* +0x000C */
+       u_short ler2_rdra;              /* +0x0010 */
+       u_short ler2_rlen;              /* +0x0012 */
+       u_short ler2_tdra;              /* +0x0014 */
+       u_short ler2_tlen;              /* +0x0016 */
+       /* receive message descriptors */
+       struct  lermd {                 /* +0x0018 */
+               u_short rmd0;
+               u_short rmd1;
+               short   rmd2;
+               u_short rmd3;
+       } ler2_rmd[LERBUF];
+       /* transmit message descriptors */
+       struct  letmd {                 /* +0x0058 */
+               u_short tmd0;
+               u_short tmd1;
+               short   tmd2;
+               u_short tmd3;
+       } ler2_tmd[LETBUF];
+       char    ler2_rbuf[LERBUF][LEMTU]; /* +0x0060 */
+       char    ler2_tbuf[LETBUF][LEMTU]; /* +0x2FD0 */
+};
+
+/*
+ * Control and status bits -- lereg0
+ */
+#define        LE_IE           0x80            /* interrupt enable */
+#define        LE_IR           0x40            /* interrupt requested */
+#define        LE_LOCK         0x08            /* lock status register */
+#define        LE_ACK          0x04            /* ack of lock */
+#define        LE_JAB          0x02            /* loss of tx clock (???) */
+#define LE_IPL(x)      ((((x) >> 4) & 0x3) + 3)
+
+/*
+ * Control and status bits -- lereg1
+ */
+#define        LE_CSR0         0
+#define        LE_CSR1         1
+#define        LE_CSR2         2
+#define        LE_CSR3         3
+
+#define        LE_SERR         0x8000
+#define        LE_BABL         0x4000
+#define        LE_CERR         0x2000
+#define        LE_MISS         0x1000
+#define        LE_MERR         0x0800
+#define        LE_RINT         0x0400
+#define        LE_TINT         0x0200
+#define        LE_IDON         0x0100
+#define        LE_INTR         0x0080
+#define        LE_INEA         0x0040
+#define        LE_RXON         0x0020
+#define        LE_TXON         0x0010
+#define        LE_TDMD         0x0008
+#define        LE_STOP         0x0004
+#define        LE_STRT         0x0002
+#define        LE_INIT         0x0001
+
+#define        LE_BSWP         0x4
+#define        LE_MODE         0x0
+
+/*
+ * Control and status bits -- lereg2
+ */
+#define        LE_OWN          0x8000
+#define        LE_ERR          0x4000
+#define        LE_STP          0x0200
+#define        LE_ENP          0x0100
+
+#define        LE_FRAM         0x2000
+#define        LE_OFLO         0x1000
+#define        LE_CRC          0x0800
+#define        LE_RBUFF        0x0400
+#define        LE_MORE         0x1000
+#define        LE_ONE          0x0800
+#define        LE_DEF          0x0400
+#define        LE_TBUFF        0x8000
+#define        LE_UFLO         0x4000
+#define        LE_LCOL         0x1000
+#define        LE_LCAR         0x0800
+#define        LE_RTRY         0x0400
diff --git a/usr/src/sys/hp300/dev/ite_dv.c b/usr/src/sys/hp300/dev/ite_dv.c
new file mode 100644 (file)
index 0000000..4e32fea
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: ite_dv.c 1.5 89/04/11$
+ *
+ *     @(#)ite_dv.c    7.1 (Berkeley) %G%
+ */
+
+#include "ite.h"
+#if NITE > 0
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+
+#include "itevar.h"
+#include "itereg.h"
+#include "grf_dvreg.h"
+
+#include "machine/cpu.h"
+
+/* XXX */
+#include "grfioctl.h"
+#include "grfvar.h"
+
+#define REGBASE                ((struct dvboxfb *)(ip->regbase))
+#define WINDOWMOVER    dvbox_windowmove
+
+dvbox_init(ip)
+       struct ite_softc *ip;
+{
+       int i;
+       
+       /* XXX */
+       if (ip->regbase == 0) {
+               struct grfinfo *gi = &grf_softc[ip - ite_softc].g_display;
+               ip->regbase = IOV(gi->gd_regaddr);
+               ip->fbbase = IOV(gi->gd_fbaddr);
+       }
+
+       dv_reset(REGADDR);
+
+       /*
+        * Turn on frame buffer, turn on overlay planes, set replacement
+        * rule, enable top overlay plane writes for ite, disable all frame
+        * buffer planes, set byte per pixel, and display frame buffer 0.
+        * Lastly, turn on the box.
+        */
+       REGBASE->interrupt = 0x04;
+       REGBASE->drive     = 0x10;              
+       REGBASE->rep_rule  = RR_COPY << 4 | RR_COPY;
+       REGBASE->opwen     = 0x01;
+       REGBASE->fbwen     = 0x0;
+       REGBASE->fold      = 0x01;
+       REGBASE->vdrive    = 0x0;
+       REGBASE->dispen    = 0x01;
+
+       /*
+        * Video enable top overlay plane.
+        */
+       REGBASE->opvenp = 0x01;
+       REGBASE->opvens = 0x01;
+
+       /*
+        * Make sure that overlay planes override frame buffer planes.
+        */
+       REGBASE->ovly0p  = 0x0;
+       REGBASE->ovly0s  = 0x0;
+       REGBASE->ovly1p  = 0x0;
+       REGBASE->ovly1s  = 0x0;
+       REGBASE->fv_trig = 0x1;
+       DELAY(100);
+
+       /*
+        * Setup the overlay colormaps. Need to set the 0,1 (black/white)
+        * color for both banks.
+        */
+
+       for (i = 0; i <= 1; i++) {
+               REGBASE->cmapbank = i;
+               REGBASE->rgb[0].red   = 0x00;
+               REGBASE->rgb[0].green = 0x00;
+               REGBASE->rgb[0].blue  = 0x00;
+               REGBASE->rgb[1].red   = 0xFF;
+               REGBASE->rgb[1].green = 0xFF;
+               REGBASE->rgb[1].blue  = 0xFF;
+       }
+       REGBASE->cmapbank = 0;
+       
+       db_waitbusy(REGADDR);
+
+       ite_devinfo(ip);
+       ite_fontinit(ip);
+
+       /*
+        * Clear the (visible) framebuffer.
+        */
+       dvbox_windowmove(ip, 0, 0, 0, 0, ip->dheight, ip->dwidth, RR_CLEAR);
+       db_waitbusy(REGADDR);
+
+       /*
+        * Stash the inverted cursor.
+        */
+       dvbox_windowmove(ip, charY(ip, ' '), charX(ip, ' '),
+                        ip->cblanky, ip->cblankx, ip->ftheight,
+                        ip->ftwidth, RR_COPYINVERTED);
+}
+
+dvbox_deinit(ip)
+       struct ite_softc *ip;
+{
+       dvbox_windowmove(ip, 0, 0, 0, 0, ip->fbheight, ip->fbwidth, RR_CLEAR);
+       db_waitbusy(REGADDR);
+
+       ip->flags &= ~ITE_INITED;
+}
+
+dvbox_putc(ip, c, dy, dx, mode)
+       register struct ite_softc *ip;
+        register int dy, dx;
+       int c, mode;
+{
+        register int wrr = ((mode == ATTR_INV) ? RR_COPYINVERTED : RR_COPY);
+       
+       dvbox_windowmove(ip, charY(ip, c), charX(ip, c),
+                        dy * ip->ftheight, dx * ip->ftwidth,
+                        ip->ftheight, ip->ftwidth, wrr);
+}
+
+dvbox_cursor(ip, flag)
+       register struct ite_softc *ip;
+        register int flag;
+{
+       if (flag == DRAW_CURSOR)
+               draw_cursor(ip)
+       else if (flag == MOVE_CURSOR) {
+               erase_cursor(ip)
+               draw_cursor(ip)
+       }
+       else
+               erase_cursor(ip)
+}
+
+dvbox_clear(ip, sy, sx, h, w)
+       struct ite_softc *ip;
+       register int sy, sx, h, w;
+{
+       dvbox_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                        sy * ip->ftheight, sx * ip->ftwidth, 
+                        h  * ip->ftheight, w  * ip->ftwidth,
+                        RR_CLEAR);
+}
+
+dvbox_scroll(ip, sy, sx, count, dir)
+        register struct ite_softc *ip;
+        register int sy, count;
+        int dir, sx;
+{
+       register int dy;
+       register int dx = sx;
+       register int height = 1;
+       register int width = ip->cols;
+
+       dvbox_cursor(ip, ERASE_CURSOR);
+
+       if (dir == SCROLL_UP) {
+               dy = sy - count;
+               height = ip->rows - sy;
+       }
+       else if (dir == SCROLL_DOWN) {
+               dy = sy + count;
+               height = ip->rows - dy - 1;
+       }
+       else if (dir == SCROLL_RIGHT) {
+               dy = sy;
+               dx = sx + count;
+               width = ip->cols - dx;
+       }
+       else {
+               dy = sy;
+               dx = sx - count;
+               width = ip->cols - sx;
+       }               
+
+       dvbox_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                        dy * ip->ftheight, dx * ip->ftwidth,
+                        height * ip->ftheight,
+                        width  * ip->ftwidth, RR_COPY);
+}
+
+dvbox_windowmove(ip, sy, sx, dy, dx, h, w, func)
+       struct ite_softc *ip;
+       int sy, sx, dy, dx, h, w, func;
+{
+       register struct dvboxfb *dp = REGBASE;
+       if (h == 0 || w == 0)
+               return;
+       
+       db_waitbusy(REGADDR);
+       dp->rep_rule = func << 4 | func;
+       dp->source_y = sy;
+       dp->source_x = sx;
+       dp->dest_y   = dy;
+       dp->dest_x   = dx;
+       dp->wheight  = h;
+       dp->wwidth   = w;
+       dp->wmove    = 1;
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/ite_gb.c b/usr/src/sys/hp300/dev/ite_gb.c
new file mode 100644 (file)
index 0000000..8aa1817
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: ite_gb.c 1.17 89/04/11$
+ *
+ *     @(#)ite_gb.c    7.1 (Berkeley) %G%
+ */
+
+#include "ite.h"
+#if NITE > 0
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+
+#include "itevar.h"
+#include "itereg.h"
+#include "grf_gbreg.h"
+
+#include "machine/cpu.h"
+
+/* XXX */
+#include "grfioctl.h"
+#include "grfvar.h"
+
+#define REGBASE        ((struct gboxfb *)(ip->regbase))
+#define WINDOWMOVER    gatorbox_windowmove
+
+gatorbox_init(ip)
+       register struct ite_softc *ip;
+{
+       /* XXX */
+       if (ip->regbase == 0) {
+               struct grfinfo *gi = &grf_softc[ip - ite_softc].g_display;
+               ip->regbase = IOV(gi->gd_regaddr);
+               ip->fbbase = IOV(gi->gd_fbaddr);
+       }
+
+       REGBASE->write_protect = 0x0;
+       REGBASE->interrupt = 0x4;
+       REGBASE->rep_rule = RR_COPY;
+       REGBASE->blink1 = 0xff;
+       REGBASE->blink2 = 0xff;
+       gb_microcode(REGADDR);
+       REGBASE->sec_interrupt = 0x01;
+
+       /*
+        * Set up the color map entries. We use three entries in the
+        * color map. The first, is for black, the second is for
+        * white, and the very last entry is for the inverted cursor.
+        */
+       REGBASE->creg_select = 0x00;
+       REGBASE->cmap_red    = 0x00;
+       REGBASE->cmap_grn    = 0x00;
+       REGBASE->cmap_blu    = 0x00;
+       REGBASE->cmap_write  = 0x00;
+       gbcm_waitbusy(REGADDR);
+       
+       REGBASE->creg_select = 0x01;
+       REGBASE->cmap_red    = 0xFF;
+       REGBASE->cmap_grn    = 0xFF;
+       REGBASE->cmap_blu    = 0xFF;
+       REGBASE->cmap_write  = 0x01;
+       gbcm_waitbusy(REGADDR);
+
+       REGBASE->creg_select = 0xFF;
+       REGBASE->cmap_red    = 0xFF;
+       REGBASE->cmap_grn    = 0xFF;
+       REGBASE->cmap_blu    = 0xFF;
+       REGBASE->cmap_write  = 0x01;
+       gbcm_waitbusy(REGADDR);
+
+       ite_devinfo(ip);
+       ite_fontinit(ip);
+
+       /*
+        * Clear the display. This used to be before the font unpacking
+        * but it crashes. Figure it out later.
+        */
+       gatorbox_windowmove(ip, 0, 0, 0, 0, ip->dheight, ip->dwidth, RR_CLEAR);
+       tile_mover_waitbusy(REGADDR);
+
+       /*
+        * Stash the inverted cursor.
+        */
+       gatorbox_windowmove(ip, charY(ip, ' '), charX(ip, ' '),
+                           ip->cblanky, ip->cblankx, ip->ftheight,
+                           ip->ftwidth, RR_COPYINVERTED);
+}
+
+gatorbox_deinit(ip)
+       struct ite_softc *ip;
+{
+       gatorbox_windowmove(ip, 0, 0, 0, 0,
+                           ip->dheight, ip->dwidth, RR_CLEAR);
+       tile_mover_waitbusy(REGADDR);
+
+       ip->flags &= ~ITE_INITED;
+}
+
+gatorbox_putc(ip, c, dy, dx, mode)
+       register struct ite_softc *ip;
+        register int dy, dx;
+       int c, mode;
+{
+        register int wrr = ((mode == ATTR_INV) ? RR_COPYINVERTED : RR_COPY);
+
+       gatorbox_windowmove(ip, charY(ip, c), charX(ip, c),
+                           dy * ip->ftheight, dx * ip->ftwidth,
+                           ip->ftheight, ip->ftwidth, wrr);
+}
+
+gatorbox_cursor(ip, flag)
+       register struct ite_softc *ip;
+        register int flag;
+{
+       if (flag == DRAW_CURSOR)
+               draw_cursor(ip)
+       else if (flag == MOVE_CURSOR) {
+               erase_cursor(ip)
+               draw_cursor(ip)
+       }
+       else
+               erase_cursor(ip)
+}
+
+gatorbox_clear(ip, sy, sx, h, w)
+       struct ite_softc *ip;
+       register int sy, sx, h, w;
+{
+       gatorbox_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                           sy * ip->ftheight, sx * ip->ftwidth, 
+                           h  * ip->ftheight, w  * ip->ftwidth,
+                           RR_CLEAR);
+}
+#define        gatorbox_blockmove(ip, sy, sx, dy, dx, h, w) \
+       gatorbox_windowmove((ip), \
+                           (sy) * ip->ftheight, \
+                           (sx) * ip->ftwidth, \
+                           (dy) * ip->ftheight, \
+                           (dx) * ip->ftwidth, \
+                           (h)  * ip->ftheight, \
+                           (w)  * ip->ftwidth, \
+                           RR_COPY)
+
+gatorbox_scroll(ip, sy, sx, count, dir)
+        register struct ite_softc *ip;
+        register int sy;
+        int dir, sx, count;
+{
+       register int height, dy, i;
+       
+       tile_mover_waitbusy(REGADDR);
+       REGBASE->write_protect = 0x0;
+       
+       gatorbox_cursor(ip, ERASE_CURSOR);
+
+       if (dir == SCROLL_UP) {
+               dy = sy - count;
+               height = ip->rows - sy;
+               for (i = 0; i < height; i++)
+                       gatorbox_blockmove(ip, sy + i, sx, dy + i, 0,
+                                          1, ip->cols);
+       }
+       else if (dir == SCROLL_DOWN) {
+               dy = sy + count;
+               height = ip->rows - dy;
+               for (i = (height - 1); i >= 0; i--)
+                       gatorbox_blockmove(ip, sy + i, sx, dy + i, 0,
+                                          1, ip->cols);
+       }
+       else if (dir == SCROLL_RIGHT) {
+               gatorbox_blockmove(ip, sy, sx, sy, sx + count,
+                                  1, ip->cols - (sx + count));
+       }
+       else {
+               gatorbox_blockmove(ip, sy, sx, sy, sx - count,
+                                  1, ip->cols - sx);
+       }               
+}
+
+gatorbox_windowmove(ip, sy, sx, dy, dx, h, w, mask)
+     register struct ite_softc *ip;
+     int sy, sx, dy, dx, mask;
+     register int h, w;
+{
+       register int src, dest;
+
+       src  = (sy * 1024) + sx;        /* upper left corner in pixels */
+       dest = (dy * 1024) + dx;
+
+       tile_mover_waitbusy(REGADDR);
+       REGBASE->width = -(w / 4);
+       REGBASE->height = -(h / 4);
+       if (src < dest)
+               REGBASE->rep_rule = MOVE_DOWN_RIGHT|mask;
+       else {
+               REGBASE->rep_rule = MOVE_UP_LEFT|mask;
+               /*
+                * Adjust to top of lower right tile of the block.
+                */
+               src = src + ((h - 4) * 1024) + (w - 4);
+               dest= dest + ((h - 4) * 1024) + (w - 4);
+       }
+       FBBASE[dest] = FBBASE[src];
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/ite_rb.c b/usr/src/sys/hp300/dev/ite_rb.c
new file mode 100644 (file)
index 0000000..6fe500e
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: ite_rb.c 1.15 89/04/11$
+ *
+ *     @(#)ite_rb.c    7.1 (Berkeley) %G%
+ */
+
+#include "ite.h"
+#if NITE > 0
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+
+#include "itevar.h"
+#include "itereg.h"
+#include "grf_rbreg.h"
+
+#include "machine/cpu.h"
+
+/* XXX */
+#include "grfioctl.h"
+#include "grfvar.h"
+
+#define REGBASE                ((struct rboxfb *)(ip->regbase))
+#define WINDOWMOVER    rbox_windowmove
+
+rbox_init(ip)
+       struct ite_softc *ip;
+{
+       register int i;
+
+       /* XXX */
+       if (ip->regbase == 0) {
+               struct grfinfo *gi = &grf_softc[ip - ite_softc].g_display;
+               ip->regbase = IOV(gi->gd_regaddr);
+               ip->fbbase = IOV(gi->gd_fbaddr);
+       }
+
+       rb_waitbusy(REGADDR);
+
+       REGBASE->reset = 0x39;
+       DELAY(1000);
+
+       REGBASE->interrupt = 0x04;
+       REGBASE->display_enable = 0x01;
+       REGBASE->video_enable = 0x01;
+       REGBASE->drive = 0x01;
+       REGBASE->vdrive = 0x0;
+
+       ite_devinfo(ip);
+       
+       REGBASE->opwen = 0xFF;
+
+       /*
+        * Clear the framebuffer.
+        */
+       rbox_windowmove(ip, 0, 0, 0, 0, ip->fbheight, ip->fbwidth, RR_CLEAR);
+       rb_waitbusy(REGADDR);
+
+       for(i = 0; i < 16; i++) {
+               *(REGADDR + 0x63c3 + i*4) = 0x0;
+               *(REGADDR + 0x6403 + i*4) = 0x0;
+               *(REGADDR + 0x6803 + i*4) = 0x0;
+               *(REGADDR + 0x6c03 + i*4) = 0x0;
+               *(REGADDR + 0x73c3 + i*4) = 0x0;
+               *(REGADDR + 0x7403 + i*4) = 0x0;
+               *(REGADDR + 0x7803 + i*4) = 0x0;
+               *(REGADDR + 0x7c03 + i*4) = 0x0;
+       }
+
+       REGBASE->rep_rule = 0x33;
+       
+       /*
+        * I cannot figure out how to make the blink planes stop. So, we
+        * must set both colormaps so that when the planes blink, and
+        * the secondary colormap is active, we still get text.
+        */
+       CM1RED[0x00].value = 0x00;
+       CM1GRN[0x00].value = 0x00;
+       CM1BLU[0x00].value = 0x00;
+       CM1RED[0x01].value = 0xFF;
+       CM1GRN[0x01].value = 0xFF;
+       CM1BLU[0x01].value = 0xFF;
+
+       CM2RED[0x00].value = 0x00;
+       CM2GRN[0x00].value = 0x00;
+       CM2BLU[0x00].value = 0x00;
+       CM2RED[0x01].value = 0xFF;
+       CM2GRN[0x01].value = 0xFF;
+       CM2BLU[0x01].value = 0xFF;
+
+       REGBASE->blink = 0x00;
+       REGBASE->write_enable = 0x01;
+       REGBASE->opwen = 0x00;
+       
+       ite_fontinit(ip);
+       
+       /*
+        * Stash the inverted cursor.
+        */
+       rbox_windowmove(ip, charY(ip, ' '), charX(ip, ' '),
+                           ip->cblanky, ip->cblankx, ip->ftheight,
+                           ip->ftwidth, RR_COPYINVERTED);
+}
+
+rbox_deinit(ip)
+       struct ite_softc *ip;
+{
+       rbox_windowmove(ip, 0, 0, 0, 0, ip->fbheight, ip->fbwidth, RR_CLEAR);
+       rb_waitbusy(REGADDR);
+
+       ip->flags &= ~ITE_INITED;
+}
+
+rbox_putc(ip, c, dy, dx, mode)
+       register struct ite_softc *ip;
+        register int dy, dx;
+       int c, mode;
+{
+        register int wrr = ((mode == ATTR_INV) ? RR_COPYINVERTED : RR_COPY);
+       
+       rbox_windowmove(ip, charY(ip, c), charX(ip, c),
+                       dy * ip->ftheight, dx * ip->ftwidth,
+                       ip->ftheight, ip->ftwidth, wrr);
+}
+
+rbox_cursor(ip, flag)
+       register struct ite_softc *ip;
+        register int flag;
+{
+       if (flag == DRAW_CURSOR)
+               draw_cursor(ip)
+       else if (flag == MOVE_CURSOR) {
+               erase_cursor(ip)
+               draw_cursor(ip)
+       }
+       else
+               erase_cursor(ip)
+}
+
+rbox_clear(ip, sy, sx, h, w)
+       struct ite_softc *ip;
+       register int sy, sx, h, w;
+{
+       rbox_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                       sy * ip->ftheight, sx * ip->ftwidth, 
+                       h  * ip->ftheight, w  * ip->ftwidth,
+                       RR_CLEAR);
+}
+
+rbox_scroll(ip, sy, sx, count, dir)
+        register struct ite_softc *ip;
+        register int sy, count;
+        int dir, sx;
+{
+       register int dy;
+       register int dx = sx;
+       register int height = 1;
+       register int width = ip->cols;
+
+       rbox_cursor(ip, ERASE_CURSOR);
+
+       if (dir == SCROLL_UP) {
+               dy = sy - count;
+               height = ip->rows - sy;
+       }
+       else if (dir == SCROLL_DOWN) {
+               dy = sy + count;
+               height = ip->rows - dy - 1;
+       }
+       else if (dir == SCROLL_RIGHT) {
+               dy = sy;
+               dx = sx + count;
+               width = ip->cols - dx;
+       }
+       else {
+               dy = sy;
+               dx = sx - count;
+               width = ip->cols - sx;
+       }               
+
+       rbox_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                       dy * ip->ftheight, dx * ip->ftwidth,
+                       height * ip->ftheight,
+                       width  * ip->ftwidth, RR_COPY);
+}
+
+rbox_windowmove(ip, sy, sx, dy, dx, h, w, func)
+       struct ite_softc *ip;
+       int sy, sx, dy, dx, h, w, func;
+{
+       register struct rboxfb *rp = REGBASE;
+       if (h == 0 || w == 0)
+               return;
+       
+       rb_waitbusy(REGADDR);
+       rp->rep_rule = func << 4 | func;
+       rp->source_y = sy;
+       rp->source_x = sx;
+       rp->dest_y = dy;
+       rp->dest_x = dx;
+       rp->wheight = h;
+       rp->wwidth  = w;
+       rp->wmove = 1;
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/ite_tc.c b/usr/src/sys/hp300/dev/ite_tc.c
new file mode 100644 (file)
index 0000000..8d3bd0e
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: ite_tc.c 1.22 89/04/11$
+ *
+ *     @(#)ite_tc.c    7.1 (Berkeley) %G%
+ */
+
+#include "ite.h"
+#if NITE > 0
+
+#include "param.h"
+#include "conf.h"
+#include "user.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "systm.h"
+#include "uio.h"
+
+#include "grf_tcreg.h"
+#include "itereg.h"
+#include "itevar.h"
+
+#include "machine/cpu.h"
+
+#define REGBASE                ((struct tcboxfb *)(ip->regbase))
+#define WINDOWMOVER    topcat_windowmove
+
+/* XXX */
+#include "grfioctl.h"
+#include "grfvar.h"
+
+topcat_init(ip)
+       register struct ite_softc *ip;
+{
+       /* XXX */
+       if (ip->regbase == NULL) {
+               struct grfinfo *gi = &grf_softc[ip - ite_softc].g_display;
+               ip->regbase = IOV(gi->gd_regaddr);
+               ip->fbbase = IOV(gi->gd_fbaddr);
+       }
+
+       /*
+        * Determine the number of planes by writing to the first frame
+        * buffer display location, then reading it back. 
+        */
+       REGBASE->wen = ~0;
+       REGBASE->fben = ~0;
+       REGBASE->prr = RR_COPY;
+       *FBBASE = 0xFF;
+       ip->planemask = *FBBASE;
+
+       /*
+        * Enable reading/writing of all the planes.
+        */
+       REGBASE->fben = ip->planemask;
+       REGBASE->wen  = ip->planemask;
+       REGBASE->ren  = ip->planemask;
+       REGBASE->prr  = RR_COPY;
+
+       ite_devinfo(ip);
+
+       /*
+        * Clear the framebuffer on all planes.
+        */
+       topcat_windowmove(ip, 0, 0, 0, 0, ip->fbheight, ip->fbwidth, RR_CLEAR);
+       tc_waitbusy(REGADDR, ip->planemask);
+
+       ite_fontinit(ip);
+
+       /*
+        * Initialize color map for color displays
+        */
+       if (ip->planemask != 1) {
+               tc_waitbusy(REGADDR, ip->planemask);
+               REGBASE->nblank = 0x01;
+
+               tccm_waitbusy(REGADDR);
+               REGBASE->rdata  = 0x0;
+               REGBASE->gdata  = 0x0;
+               REGBASE->bdata  = 0x0;
+               REGBASE->cindex = 0xFF;
+               REGBASE->strobe = 0xFF;
+
+               DELAY(100);
+               tccm_waitbusy(REGADDR);
+               REGBASE->rdata  = 0x0;
+               REGBASE->gdata  = 0x0;
+               REGBASE->bdata  = 0x0;
+               REGBASE->cindex = 0x0;
+
+               DELAY(100);
+               tccm_waitbusy(REGADDR);
+               REGBASE->rdata  = 0xFF;
+               REGBASE->gdata  = 0xFF;
+               REGBASE->bdata  = 0xFF;
+               REGBASE->cindex = 0xFE;
+               REGBASE->strobe = 0xFF;
+
+               DELAY(100);
+               tccm_waitbusy(REGADDR);
+               REGBASE->rdata  = 0x0;
+               REGBASE->gdata  = 0x0;
+               REGBASE->bdata  = 0x0;
+               REGBASE->cindex = 0x0;
+       }
+
+       /*
+        * Stash the inverted cursor.
+        */
+       topcat_windowmove(ip, charY(ip, ' '), charX(ip, ' '),
+                         ip->cblanky, ip->cblankx, ip->ftheight,
+                         ip->ftwidth, RR_COPYINVERTED);
+}
+
+topcat_deinit(ip)
+       register struct ite_softc *ip;
+{
+       topcat_windowmove(ip, 0, 0, 0, 0, ip->fbheight, ip->fbwidth, RR_CLEAR);
+       tc_waitbusy(REGADDR, ip->planemask);
+
+       REGBASE->nblank = ~0;
+       ip->flags &= ~ITE_INITED;
+}
+
+topcat_putc(ip, c, dy, dx, mode)
+       register struct ite_softc *ip;
+       int c, dy, dx, mode;
+{
+        int wmrr = ((mode == ATTR_INV) ? RR_COPYINVERTED : RR_COPY);
+       
+       topcat_windowmove(ip, charY(ip, c), charX(ip, c),
+                         dy * ip->ftheight, dx * ip->ftwidth,
+                         ip->ftheight, ip->ftwidth, wmrr);
+}
+
+topcat_cursor(ip, flag)
+       register struct ite_softc *ip;
+       register int flag;
+{
+       if (flag == DRAW_CURSOR)
+               draw_cursor(ip)
+       else if (flag == MOVE_CURSOR) {
+               erase_cursor(ip)
+               draw_cursor(ip)
+       }
+       else
+               erase_cursor(ip)
+}
+
+topcat_clear(ip, sy, sx, h, w)
+       register struct ite_softc *ip;
+       register int sy, sx, h, w;
+{
+       topcat_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                         sy * ip->ftheight, sx * ip->ftwidth, 
+                         h  * ip->ftheight, w  * ip->ftwidth,
+                         RR_CLEAR);
+}
+
+topcat_scroll(ip, sy, sx, count, dir)
+        register struct ite_softc *ip;
+        register int sy, count;
+        int dir, sx;
+{
+       register int dy;
+       register int dx = sx;
+       register int height = 1;
+       register int width = ip->cols;
+
+       topcat_cursor(ip, ERASE_CURSOR);
+
+       if (dir == SCROLL_UP) {
+               dy = sy - count;
+               height = ip->rows - sy;
+       }
+       else if (dir == SCROLL_DOWN) {
+               dy = sy + count;
+               height = ip->rows - dy - 1;
+       }
+       else if (dir == SCROLL_RIGHT) {
+               dy = sy;
+               dx = sx + count;
+               width = ip->cols - dx;
+       }
+       else {
+               dy = sy;
+               dx = sx - count;
+               width = ip->cols - sx;
+       }               
+
+       topcat_windowmove(ip, sy * ip->ftheight, sx * ip->ftwidth,
+                         dy * ip->ftheight, dx * ip->ftwidth,
+                         height * ip->ftheight,
+                         width  * ip->ftwidth, RR_COPY);
+}
+
+topcat_windowmove(ip, sy, sx, dy, dx, h, w, func)
+       struct ite_softc *ip;
+       int sy, sx, dy, dx, h, w, func;
+{
+       register struct tcboxfb *rp = REGBASE;
+       
+       if (h == 0 || w == 0)
+               return;
+       tc_waitbusy(REGADDR, ip->planemask);
+       rp->wmrr     = func;
+       rp->source_y = sy;
+       rp->source_x = sx;
+       rp->dest_y   = dy;
+       rp->dest_x   = dx;
+       rp->wheight  = h;
+       rp->wwidth   = w;
+       rp->wmove    = ip->planemask;
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/nhpib.c b/usr/src/sys/hp300/dev/nhpib.c
new file mode 100644 (file)
index 0000000..8bf6547
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)nhpib.c     7.1 (Berkeley) %G%
+ */
+
+/*
+ * Internal/98624 HPIB driver
+ */
+#include "hpib.h"
+#if NHPIB > 0
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "device.h"
+#include "nhpibreg.h"
+#include "hpibvar.h"
+#include "dmavar.h"
+
+nhpibtype(hc)
+       register struct hp_ctlr *hc;
+{
+       register struct hpib_softc *hs = &hpib_softc[hc->hp_unit];
+       register struct nhpibdevice *hd = (struct nhpibdevice *)hc->hp_addr;
+
+       if ((int)hc->hp_addr == internalhpib) {
+               hs->sc_type = HPIBA;
+               hs->sc_ba = HPIBA_BA;
+               hc->hp_ipl = HPIBA_IPL;
+       }
+       else if (hd->hpib_cid == HPIBB) {
+               hs->sc_type = HPIBB;
+               hs->sc_ba = hd->hpib_csa & CSA_BA;
+               hc->hp_ipl = HPIB_IPL(hd->hpib_ids);
+       }
+       else
+               return(0);
+       return(1);
+}
+
+nhpibreset(unit)
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_acr = AUX_SSWRST;
+       hd->hpib_ar = hs->sc_ba;
+       hd->hpib_lim = LIS_ERR;
+       hd->hpib_mim = 0;
+       hd->hpib_acr = AUX_CDAI;
+       hd->hpib_acr = AUX_CSHDW;
+       hd->hpib_acr = AUX_SSTD1;
+       hd->hpib_acr = AUX_SVSTD1;
+       hd->hpib_acr = AUX_CPP;
+       hd->hpib_acr = AUX_CHDFA;
+       hd->hpib_acr = AUX_CHDFE;
+       hd->hpib_acr = AUX_RHDF;
+       hd->hpib_acr = AUX_CSWRST;
+       nhpibifc(hd);
+       hd->hpib_ie = IDS_IE;
+       hd->hpib_data = C_DCL;
+       DELAY(100000);
+}
+
+nhpibifc(hd)
+       register struct nhpibdevice *hd;
+{
+       hd->hpib_acr = AUX_TCA;
+       hd->hpib_acr = AUX_CSRE;
+       hd->hpib_acr = AUX_SSIC;
+       DELAY(100);
+       hd->hpib_acr = AUX_CSIC;
+       hd->hpib_acr = AUX_SSRE;
+}
+
+nhpibsend(unit, slave, sec, addr, cnt)
+       register char *addr;
+       register int cnt;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+       register int origcnt = cnt;
+
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_acr = AUX_TCA;
+       hd->hpib_data = C_UNL;
+       nhpibowait(hd);
+       hd->hpib_data = C_TAG + hs->sc_ba;
+       hd->hpib_acr = AUX_STON;
+       nhpibowait(hd);
+       hd->hpib_data = C_LAG + slave;
+       nhpibowait(hd);
+       if (sec != -1) {
+               hd->hpib_data = C_SCG + sec;
+               nhpibowait(hd);
+       }
+       hd->hpib_acr = AUX_GTS;
+       if (cnt) {
+               while (--cnt) {
+                       hd->hpib_data = *addr++;
+                       if (nhpibowait(hd) < 0) {
+                               nhpibifc(hd);
+                               cnt++;
+                               goto out;
+                       }
+               }
+               hd->hpib_acr = AUX_EOI;
+               hd->hpib_data = *addr;
+               if (nhpibowait(hd) < 0) {
+                       nhpibifc(hd);
+                       cnt++;
+               }
+               else
+                       hd->hpib_acr = AUX_TCA;
+       }
+out:
+       return(origcnt - cnt);
+}
+
+nhpibrecv(unit, slave, sec, addr, cnt)
+       register char *addr;
+       register int cnt;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+       register int origcnt = cnt;
+
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_acr = AUX_TCA;
+       hd->hpib_data = C_UNL;
+       nhpibowait(hd);
+       hd->hpib_data = C_LAG + hs->sc_ba;
+       hd->hpib_acr = AUX_SLON;
+       nhpibowait(hd);
+       hd->hpib_data = C_TAG + slave;
+       nhpibowait(hd);
+       if (sec != -1) {
+               hd->hpib_data = C_SCG + sec;
+               nhpibowait(hd);
+       }
+       hd->hpib_acr = AUX_RHDF;
+       hd->hpib_acr = AUX_GTS;
+       if (cnt) {
+               while (--cnt >= 0) {
+                       if (nhpibiwait(hd) < 0) {
+                               nhpibifc(hd);
+                               break;
+                       }
+                       *addr++ = hd->hpib_data;
+               }
+               cnt++;
+               hd->hpib_acr = AUX_TCA;
+       }
+       return(origcnt - cnt);
+}
+
+nhpibgo(unit, slave, sec, addr, count, rw)
+       register int unit, slave;
+       char *addr;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       hs->sc_flags |= HPIBF_IO;
+       if (rw == B_READ)
+               hs->sc_flags |= HPIBF_READ;
+#ifdef DEBUG
+       else if (hs->sc_flags & HPIBF_READ) {
+               printf("nhpibgo: HPIBF_READ still set\n");
+               hs->sc_flags &= ~HPIBF_READ;
+       }
+#endif
+       hs->sc_count = count;
+       hs->sc_addr = addr;
+       if (hs->sc_flags & HPIBF_READ) {
+               hs->sc_curcnt = count;
+               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);
+               }
+       }
+       hd->hpib_ie = IDS_IE | IDS_DMA(hs->sc_dq.dq_ctlr);
+}
+
+nhpibdone(unit)
+       register int unit;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+       register int cnt;
+
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       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 {
+               if (hs->sc_count == 1) {
+                       hs->sc_curcnt = 1;
+                       hd->hpib_acr = AUX_EOI;
+                       dmago(hs->sc_dq.dq_ctlr, hs->sc_addr, 1, DMAGO_BYTE);
+                       return;
+               }
+               hs->sc_flags |= HPIBF_DONE;
+               hd->hpib_ie = IDS_IE;
+               hd->hpib_mim = MIS_BO;
+       }
+}
+
+nhpibintr(unit)
+       register int unit;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+       register struct devqueue *dq = hs->sc_sq.dq_forw;
+       register int stat0;
+       int stat1;
+
+#ifdef lint
+       if (stat1 = unit) return(1);
+#endif
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       if ((hd->hpib_ids & IDS_IR) == 0)
+               return(0);
+       stat0 = hd->hpib_mis;
+       stat1 = hd->hpib_lis;
+       if (hs->sc_flags & HPIBF_IO) {
+               hd->hpib_mim = 0;
+               if ((hs->sc_flags & HPIBF_DONE) == 0)
+                       dmastop(hs->sc_dq.dq_ctlr);
+               hd->hpib_acr = AUX_TCA;
+               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) {
+               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);
+       }
+       return(1);
+}
+
+nhpibppoll(unit)
+       register int unit;
+{
+       register struct hpib_softc *hs = &hpib_softc[unit];
+       register struct nhpibdevice *hd;
+       register int ppoll;
+
+       hd = (struct nhpibdevice *)hs->sc_hc->hp_addr;
+       hd->hpib_acr = AUX_SPP;
+       DELAY(25);
+       ppoll = hd->hpib_cpt;
+       hd->hpib_acr = AUX_CPP;
+       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)
+       register struct nhpibdevice *hd;
+{
+       extern int hpibtimeout;
+       register int timo = hpibtimeout;
+
+       while ((hd->hpib_mis & MIS_BI) == 0 && --timo)
+               ;
+       if (timo == 0)
+               return(-1);
+       return(0);
+}
+
+nhpibppwatch(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 (nhpibppoll(unit) & slave)
+                       ((struct nhpibdevice *)hs->sc_hc->hp_addr)->hpib_mim = MIS_BO;
+       else
+               timeout(nhpibppwatch, unit, 1);
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/nhpibreg.h b/usr/src/sys/hp300/dev/nhpibreg.h
new file mode 100644 (file)
index 0000000..c574407
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)nhpibreg.h  7.1 (Berkeley) %G%
+ */
+
+#define        vu_char volatile u_char
+
+#define        LIS_SRQ         0x02
+#define        LIS_ERR         0x40
+
+#define        MIS_END         0x08
+#define        MIS_BO          0x10
+#define        MIS_BI          0x20
+
+#define        IS_TADS         0x02
+#define        IS_LADS         0x04
+
+#define        AUX_CSWRST      0
+#define        AUX_RHDF        2
+#define        AUX_CHDFA       3
+#define        AUX_CHDFE       4
+#define        AUX_EOI         8
+#define        AUX_GTS         11
+#define        AUX_TCA         12
+#define        AUX_TCS         13
+#define        AUX_CPP         14
+#define        AUX_CSIC        15
+#define        AUX_CSRE        16
+#define        AUX_CDAI        19
+#define        AUX_CSHDW       22
+#define        AUX_SSWRST      128
+#define        AUX_SHDFE       132
+#define        AUX_SLON        137
+#define        AUX_STON        138
+#define        AUX_SPP         142
+#define        AUX_SSIC        143
+#define        AUX_SSRE        144
+#define        AUX_SSTD1       149
+#define        AUX_SVSTD1      151
+
+struct nhpibdevice {
+       u_char  hpib_pad0;
+       vu_char hpib_cid;
+       u_char  hpib_pad1;
+#define        hpib_ie         hpib_ids
+       vu_char hpib_ids;
+       u_char  hpib_pad2;
+       vu_char hpib_csa;
+       u_char  hpib_pad3[11];
+#define        hpib_mim        hpib_mis
+       vu_char hpib_mis;
+       u_char  hpib_pad4;
+#define        hpib_lim        hpib_lis
+       vu_char hpib_lis;
+       u_char  hpib_pad5;
+       vu_char hpib_is;
+       u_char  hpib_pad6;
+#define        hpib_acr        hpib_cls
+       vu_char hpib_cls;
+       u_char  hpib_pad7;
+       vu_char hpib_ar;
+       u_char  hpib_pad8;
+       vu_char hpib_sprb;
+       u_char  hpib_pad9;
+#define        hpib_ppr        hpib_cpt
+       vu_char hpib_cpt;
+       u_char  hpib_pad10;
+       vu_char hpib_data;
+};
diff --git a/usr/src/sys/hp300/dev/ppi.c b/usr/src/sys/hp300/dev/ppi.c
new file mode 100644 (file)
index 0000000..b03b25d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ppi.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ * Printer/Plotter HPIB interface
+ */
+
+#include "ppi.h"
+#if NPPI > 0
+
+#include "param.h"
+#include "errno.h"
+#include "uio.h"
+#include "malloc.h"
+
+#include "device.h"
+
+int    ppiattach(), ppistart();
+struct driver ppidriver = {
+       ppiattach, "ppi", ppistart,
+};
+
+struct ppi_softc {
+       int     sc_flags;
+       struct  devqueue sc_dq;
+       struct  hp_device *sc_hd;
+} ppi_softc[NPPI];
+
+/* sc_flags values */
+#define        PPIF_ALIVE      0x1     
+#define        PPIF_OPEN       0x2     
+
+#define UNIT(x)                minor(x)
+
+ppiattach(hd)
+       register struct hp_device *hd;
+{
+       register struct ppi_softc *sc = &ppi_softc[hd->hp_unit];
+
+       /*
+        * XXX: the printer/plotter doesn't seem to really return
+        * an ID but this will at least prevent us from mistaking
+        * a cs80 disk or tape for a ppi device.
+        */
+       if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200)
+               return(0);
+       sc->sc_flags = PPIF_ALIVE;
+       sc->sc_dq.dq_ctlr = hd->hp_ctlr;
+       sc->sc_dq.dq_unit = hd->hp_unit;
+       sc->sc_dq.dq_slave = hd->hp_slave;
+       sc->sc_dq.dq_driver = &ppidriver;
+       sc->sc_hd = hd;
+       return(1);
+}
+
+ppiopen(dev, flags)
+       dev_t dev;
+{
+       register int unit = UNIT(dev);
+       register struct ppi_softc *sc = &ppi_softc[unit];
+
+       if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0)
+               return(ENXIO);
+       if (sc->sc_flags & PPIF_OPEN)
+               return(EBUSY);
+       sc->sc_flags |= PPIF_OPEN;
+       return(0);
+}
+
+ppiclose(dev, flags)
+       dev_t dev;
+{
+       register int unit = UNIT(dev);
+       register struct ppi_softc *sc = &ppi_softc[unit];
+
+       sc->sc_flags &= ~PPIF_OPEN;
+       return(0);
+}
+
+ppistart(unit)
+       register int unit;
+{
+       wakeup(&ppi_softc[unit]);
+}
+
+ppiread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+
+       return (ppirw(dev, uio, UIO_READ));
+}
+
+ppiwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+
+       return (ppirw(dev, uio, UIO_WRITE));
+}
+
+ppirw(dev, uio, rw)
+       dev_t dev;
+       register struct uio *uio;
+       enum uio_rw rw;
+{
+       register struct ppi_softc *sc = &ppi_softc[UNIT(dev)];
+       register int s, len, cnt;
+       register char *cp;
+       int error = 0;
+
+       len = MIN(CLBYTES, uio->uio_resid);
+       cp = (char *)malloc(len, M_TEMP, M_WAITOK);
+       while (uio->uio_resid > 0) {
+               len = MIN(CLBYTES, uio->uio_resid);
+               if (rw == UIO_WRITE) {
+                       error = uiomove(cp, len, uio);
+                       if (error)
+                               break;
+               }
+               s = splbio();
+               if (hpibreq(&sc->sc_dq) == 0)
+                       sleep(sc, PRIBIO + 1);
+               splx(s);
+               if (rw == UIO_WRITE)
+                       cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                               -1, cp, len);
+               else
+                       cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
+                               -1, cp, len);
+               s = splbio();
+               hpibfree(&sc->sc_dq);
+               splx(s);
+               if (rw == UIO_READ) {
+                       error = uiomove(cp, cnt, uio);
+                       if (error)
+                               break;
+               }
+               if (cnt != len) {
+                       if (rw == UIO_WRITE)
+                               uio->uio_resid += len - cnt;
+                       break;
+               }
+       }
+       free(cp, M_TEMP);
+       return (error);
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/rd.c b/usr/src/sys/hp300/dev/rd.c
new file mode 100644 (file)
index 0000000..e7101e1
--- /dev/null
@@ -0,0 +1,1091 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: rd.c 1.30 89/09/17$
+ *
+ *     @(#)rd.c        7.1 (Berkeley) %G%
+ */
+
+/*
+ * CS80/SS80 disk driver
+ */
+#include "rd.h"
+#if NRD > 0
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "dkstat.h"
+#include "disklabel.h"
+#include "buf.h"
+#include "uio.h"
+
+#include "device.h"
+#include "rdreg.h"
+
+int    rdinit(), rdstart(), rdgo(), rdintr();
+struct driver rddriver = {
+       rdinit, "rd", rdstart, rdgo, rdintr,
+};
+
+struct rd_softc {
+       struct  hp_device *sc_hd;
+       struct  rd_iocmd sc_ioc;
+       struct  rd_rscmd sc_rsc;
+       struct  rd_stat sc_stat;
+       struct  rd_ssmcmd sc_ssmc;
+       struct  rd_srcmd sc_src;
+       struct  rd_clearcmd sc_clear;
+       int     sc_resid;
+       char    *sc_addr;
+       struct  rdinfo *sc_info;
+       int     sc_flags;
+       short   sc_type;
+       short   sc_punit;
+       struct  devqueue sc_dq;
+} rd_softc[NRD];
+
+/* sc_flags values */
+#define        RDF_ALIVE       0x1
+#define        RDF_SEEK        0x2
+#define RDF_SWAIT      0x4
+
+struct size {
+       daddr_t nblocks;
+       int     cyloff;
+};
+
+#ifdef DEBUG
+int rddebug = 0x80;
+#define RDB_FOLLOW     0x01
+#define RDB_STATUS     0x02
+#define RDB_IDENT      0x04
+#define RDB_IO         0x08
+#define RDB_ASYNC      0x10
+#define RDB_ERROR      0x80
+#define RDB_DUMP       0x80000000
+
+struct rdstats {
+       long    rdretries;
+       long    rdresets;
+       long    rdtimeouts;
+       long    rdpolltries;
+       long    rdpollwaits;
+} rdstats[NRD];
+
+/* error message tables */
+char *err_reject[] = {
+       0, 0,
+       "channel parity error",         /* 0x2000 */
+       0, 0,
+       "illegal opcode",               /* 0x0400 */
+       "module addressing",            /* 0x0200 */
+       "address bounds",               /* 0x0100 */
+       "parameter bounds",             /* 0x0080 */
+       "illegal parameter",            /* 0x0040 */
+       "message sequence",             /* 0x0020 */
+       0,
+       "message length",               /* 0x0008 */
+       0, 0, 0
+};
+
+char *err_fault[] = {
+       0,
+       "cross unit",                   /* 0x4000 */
+       0,
+       "controller fault",             /* 0x1000 */
+       0, 0,
+       "unit fault",                   /* 0x0200 */
+       0,
+       "diagnostic result",            /* 0x0080 */
+       0,
+       "operator release request",     /* 0x0020 */
+       "diagnostic release request",   /* 0x0010 */
+       "internal maintenance release request", /* 0x0008 */
+       0,
+       "power fail",                   /* 0x0002 */
+       "retransmit"                    /* 0x0001 */
+};
+
+char *err_access[] = {
+       "illegal parallel operation",   /* 0x8000 */
+       "uninitialized media",          /* 0x4000 */
+       "no spares available",          /* 0x2000 */
+       "not ready",                    /* 0x1000 */
+       "write protect",                /* 0x0800 */
+       "no data found",                /* 0x0400 */
+       0, 0,
+       "unrecoverable data overflow",  /* 0x0080 */
+       "unrecoverable data",           /* 0x0040 */
+       0,
+       "end of file",                  /* 0x0010 */
+       "end of volume",                /* 0x0008 */
+       0, 0, 0
+};
+
+char *err_info[] = {
+       "operator release request",     /* 0x8000 */
+       "diagnostic release request",   /* 0x4000 */
+       "internal maintenance release request", /* 0x2000 */
+       "media wear",                   /* 0x1000 */
+       "latency induced",              /* 0x0800 */
+       0, 0,
+       "auto sparing invoked",         /* 0x0100 */
+       0,
+       "recoverable data overflow",    /* 0x0040 */
+       "marginal data",                /* 0x0020 */
+       "recoverable data",             /* 0x0010 */
+       0,
+       "maintenance track overflow",   /* 0x0004 */
+       0, 0
+};
+#endif
+
+/*
+ * CS/80 partitions.  We reserve the first cylinder for a LIF
+ * style boot directory (the 8k allowed in the BSD filesystem
+ * is just way too small).  This boot area is outside of all but
+ * the C partition.  This implies that you cannot use the C 
+ * partition on a bootable disk since the filesystem would overlay
+ * the boot area.  You must use the A partition.
+ *
+ * These maps support four basic layouts:
+ *
+ *     A/B/G:   This is the "traditional" setup for a bootable disk.
+ *              A is the root partition, B the swap, and G a user partition.
+ *     A/D/H:   This is a setup for bootable systems requiring more swap
+ *              (e.g. those who use HPCL).  It has A as the root, D as a
+ *              larger swap, and H as a smaller user partition.
+ *     A/D/E/F: Similar to A/D/H with E and F breaking H into two partitions.
+ *              E could be used for /usr and F for users.
+ *     C:       This gives a single, non-bootable, large user filesystem.
+ *              Good for second drives on a machine (e.g. /usr/src).
+ */
+struct size rd7945A_sizes[8] = {
+       RDSZ(15904),    1,              /* A=cyl 1 thru 142 */
+       RDSZ(20160),    143,            /* B=cyl 143 thru 322 */
+       RDSZ(108416),   0,              /* C=cyl 0 thru 967 */
+       RDSZ(40320),    143,            /* D=cyl 143 thru 502 */
+       RDSZ(0),        0,              /* E=<undefined> */
+       RDSZ(0),        0,              /* F=<undefined> */
+       RDSZ(72240),    323,            /* G=cyl 323 thru 967 */
+       RDSZ(52080),    503,            /* H=cyl 503 thru 967 */
+}, rd9134D_sizes[8] = {
+       RDSZ(15936),    1,              /* A=cyl 1 thru 166 */
+       RDSZ(13056),    167,            /* B=cyl 167 thru 302 */
+       RDSZ(29088),    0,              /* C=cyl 0 thru 302 */
+       RDSZ(0),        0,              /* D=<undefined> */
+       RDSZ(0),        0,              /* E=<undefined> */
+       RDSZ(0),        0,              /* F=<undefined> */
+       RDSZ(0),        0,              /* G=<undefined> */
+       RDSZ(0),        0,              /* H=<undefined> */
+}, rd9122S_sizes[8] = {
+       RDSZ(0),        0,              /* A=<undefined> */
+       RDSZ(0),        0,              /* B=<undefined> */
+       RDSZ(1232),     0,              /* C=cyl 0 thru 76 */
+       RDSZ(0),        0,              /* D=<undefined> */
+       RDSZ(0),        0,              /* E=<undefined> */
+       RDSZ(0),        0,              /* F=<undefined> */
+       RDSZ(0),        0,              /* G=<undefined> */
+       RDSZ(0),        0,              /* H=<undefined> */
+}, rd7912P_sizes[8] = {
+       RDSZ(15904),    0,              /* A=cyl 1 thru 71 */
+       RDSZ(22400),    72,             /* B=cyl 72 thru 171 */
+       RDSZ(128128),   0,              /* C=cyl 0 thru 571 */
+       RDSZ(42560),    72,             /* D=cyl 72 thru 261 */
+       RDSZ(0),        292,            /* E=<undefined> */
+       RDSZ(0),        542,            /* F=<undefined> */
+       RDSZ(89600),    172,            /* G=cyl 221 thru 571 */
+       RDSZ(69440),    262,            /* H=cyl 262 thru 571 */
+}, rd7914P_sizes[8] = {
+       RDSZ(15904),    1,              /* A=cyl 1 thru 71 */
+       RDSZ(40320),    72,             /* B=cyl 72 thru 251 */
+       RDSZ(258048),   0,              /* C=cyl 0 thru 1151 */
+       RDSZ(64960),    72,             /* D=cyl 72 thru 361 */
+       RDSZ(98560),    362,            /* E=cyl 362 thru 801 */
+       RDSZ(78400),    802,            /* F=cyl 802 thru 1151 */
+       RDSZ(201600),   252,            /* G=cyl 221 thru 1151 */
+       RDSZ(176960),   362,            /* H=cyl 362 thru 1151 */
+}, rd7933H_sizes[8] = {
+       RDSZ(16146),    1,              /* A=cyl 1 thru 27 */
+       RDSZ(66976),    28,             /* B=cyl 28 thru 139 */
+       RDSZ(789958),   0,              /* C=cyl 0 thru 1320 */
+       RDSZ(16146),    140,            /* D=cyl 140 thru 166 */
+       RDSZ(165646),   167,            /* E=cyl 167 thru 443 */
+       RDSZ(165646),   444,            /* F=cyl 444 thru 720 */
+       RDSZ(706238),   140,            /* G=cyl 140 thru 1320 */
+       RDSZ(358800),   721,            /* H=cyl 721 thru 1320 */
+}, rd9134L_sizes[8] = {
+       RDSZ(15920),    1,              /* A=cyl 1 thru 199 */
+       RDSZ(20000),    200,            /* B=cyl 200 thru 449 */
+       RDSZ(77840),    0,              /* C=cyl 0 thru 972 */
+       RDSZ(32000),    200,            /* D=cyl 200 thru 599 */
+       RDSZ(0),        0,              /* E=<undefined> */
+       RDSZ(0),        0,              /* F=<undefined> */
+       RDSZ(41840),    450,            /* G=cyl 450 thru 972 */
+       RDSZ(29840),    600,            /* H=cyl 600 thru 972 */
+}, rd7957A_sizes[8] = {
+       RDSZ(16016),    1,              /* A=cyl 1 thru 104 */
+       RDSZ(24640),    105,            /* B=cyl 105 thru 264 */
+       RDSZ(159544),   0,              /* C=cyl 0 thru 1035 */
+       RDSZ(42350),    105,            /* D=cyl 105 thru 379 */
+       RDSZ(54824),    380,            /* E=cyl 380 thru 735 */
+       RDSZ(46200),    736,            /* F=cyl 736 thru 1035 */
+       RDSZ(118734),   265,            /* G=cyl 265 thru 1035 */
+       RDSZ(101024),   380,            /* H=cyl 380 thru 1035 */
+}, rd7958A_sizes[8] = {
+       RDSZ(16128),    1,              /* A=cyl 1 thru 64 */
+       RDSZ(32256),    65,             /* B=cyl 65 thru 192 */
+       RDSZ(255276),   0,              /* C=cyl 0 thru 1012 */
+       RDSZ(48384),    65,             /* D=cyl 65 thru 256 */
+       RDSZ(100800),   257,            /* E=cyl 257 thru 656 */
+       RDSZ(89712),    657,            /* F=cyl 657 thru 1012 */
+       RDSZ(206640),   193,            /* G=cyl 193 thru 1012 */
+       RDSZ(190512),   257,            /* H=cyl 257 thru 1012 */
+}, rd7957B_sizes[8] = {
+       RDSZ(16002),    1,              /* A=cyl 1 thru 127 */
+       RDSZ(32760),    128,            /* B=cyl 128 thru 387 */
+       RDSZ(159894),   0,              /* C=cyl 0 thru 1268 */
+       RDSZ(49140),    128,            /* D=cyl 128 thru 517 */
+       RDSZ(50400),    518,            /* E=cyl 518 thru 917 */
+       RDSZ(44226),    918,            /* F=cyl 918 thru 1268 */
+       RDSZ(111006),   388,            /* G=cyl 388 thru 1268 */
+       RDSZ(94626),    518,            /* H=cyl 518 thru 1268 */
+}, rd7958B_sizes[8] = {
+       RDSZ(16254),    1,              /* A=cyl 1 thru 43 */
+       RDSZ(32886),    44,             /* B=cyl 44 thru 130 */
+       RDSZ(297108),   0,              /* C=cyl 0 thru 785 */
+       RDSZ(49140),    44,             /* D=cyl 44 thru 173 */
+       RDSZ(121716),   174,            /* E=cyl 174 thru 495 */
+       RDSZ(109620),   496,            /* F=cyl 496 thru 785 */
+       RDSZ(247590),   131,            /* G=cyl 131 thru 785 */
+       RDSZ(231336),   174,            /* H=cyl 174 thru 785 */
+}, rd7959B_sizes[8] = {
+       RDSZ(16254),    1,              /* A=cyl 1 thru 43 */
+       RDSZ(49140),    44,             /* B=cyl 44 thru 173 */
+       RDSZ(594216),   0,              /* C=cyl 0 thru 1571 */
+       RDSZ(65772),    44,             /* D=cyl 44 thru 217 */
+       RDSZ(303912),   218,            /* E=cyl 218 thru 1021 */
+       RDSZ(207900),   1022,           /* F=cyl 1022 thru 1571 */
+       RDSZ(528444),   174,            /* G=cyl 174 thru 1571 */
+       RDSZ(511812),   218,            /* H=cyl 218 thru 1571 */
+
+#if DEV_BSIZE == 512
+/*
+ * These values would not work for 1k,
+ * since the number of cylinders would be different.
+ */
+}, rd7936H_sizes[8] = {
+       RDSZ(16359),    1,              /* A=cyl 1 thru 19 */
+       RDSZ(67158),    20,             /* B=cyl 20 thru 97 */
+       RDSZ(600978),   0,              /* C=cyl 0 thru 697 */
+       RDSZ(16359),    98,             /* D=cyl 98 thru 116 */
+       RDSZ(120540),   117,            /* E=cyl 117 thru 256 */
+       RDSZ(120540),   256,            /* F=cyl 256 thru 396 */
+       RDSZ(516600),   98,             /* G=cyl 98 thru 697 */
+       RDSZ(259161),   397,            /* H=cyl 397 thru 697 */
+}, rd7937H_sizes[8] = {
+#ifdef UTAH
+       RDSZ(15990),    1,              /* A=cyl 1 thru 10 */
+       RDSZ(67158),    11,             /* B=cyl 11 thru 52 */
+       RDSZ(1116102),  0,              /* C=cyl 0 thru 697 */
+       RDSZ(124722),   53,             /* D=cyl 53 thru 130 */
+       RDSZ(163098),   131,            /* E=cyl 131 thru 232 */
+       RDSZ(287820),   233,            /* F=cyl 233 thru 412 */
+       RDSZ(1031355),  53,             /* G=cyl 53 thru 697 */
+       RDSZ(455715),   413,            /* H=cyl 413 thru 697 */
+#else
+       RDSZ(15990),    1,              /* A=cyl 1 thru 10 */
+       RDSZ(67158),    11,             /* B=cyl 11 thru 52 */
+       RDSZ(1116102),  0,              /* C=cyl 0 thru 697 */
+       RDSZ(15990),    53,             /* D=cyl 53 thru 62 */
+       RDSZ(246246),   63,             /* E=cyl 63 thru 216 */
+       RDSZ(246246),   217,            /* F=cyl 217 thru 370 */
+       RDSZ(1031355),  53,             /* G=cyl 53 thru 697 */
+       RDSZ(522873),   371,            /* H=cyl 371 thru 697 */
+#endif
+#endif
+};
+
+struct rdinfo {
+       int     nbpt;           /* DEV_BSIZE blocks per track */
+       int     ntpc;           /* tracks per cylinder */
+       int     nbpc;           /* blocks per cylinder */
+       struct  size *sizes;    /* default partition info (if no disklabel) */
+       short   hwid;           /* 2 byte HW id */
+       short   maxunum;        /* maximum allowed unit number */
+       char    *desc;          /* drive type description */
+};
+
+struct rdinfo rdinfo[] = {
+       NRD7945ABPT,    NRD7945ATRK,    NRD7945ABPT * NRD7945ATRK,
+       rd7945A_sizes,  RD7946AID,      0,      "7945A",
+       NRD9134DBPT,    NRD9134DTRK,    NRD9134DBPT * NRD9134DTRK,
+       rd9134D_sizes,  RD9134DID,      1,      "9134D",
+       NRD9122SBPT,    NRD9122STRK,    NRD9122SBPT * NRD9122STRK,
+       rd9122S_sizes,  RD9134LID,      1,      "9122S",
+       NRD7912PBPT,    NRD7912PTRK,    NRD7912PBPT * NRD7912PTRK,
+       rd7912P_sizes,  RD7912PID,      0,      "7912P",
+       NRD7914PBPT,    NRD7914PTRK,    NRD7914PBPT * NRD7914PTRK,
+       rd7914P_sizes,  RD7914PID,      0,      "7914P",
+       NRD7958ABPT,    NRD7958ATRK,    NRD7958ABPT * NRD7958ATRK,
+       rd7958A_sizes,  RD7958AID,      0,      "7958A",
+       NRD7957ABPT,    NRD7957ATRK,    NRD7957ABPT * NRD7957ATRK,
+       rd7957A_sizes,  RD7957AID,      0,      "7957A",
+       NRD7933HBPT,    NRD7933HTRK,    NRD7933HBPT * NRD7933HTRK,
+       rd7933H_sizes,  RD7933HID,      0,      "7933H",
+       NRD9134LBPT,    NRD9134LTRK,    NRD9134LBPT * NRD9134LTRK,
+       rd9134L_sizes,  RD9134LID,      1,      "9134L",
+       NRD7936HBPT,    NRD7936HTRK,    NRD7936HBPT * NRD7936HTRK,
+       rd7936H_sizes,  RD7936HID,      0,      "7936H",
+       NRD7937HBPT,    NRD7937HTRK,    NRD7937HBPT * NRD7937HTRK,
+       rd7937H_sizes,  RD7937HID,      0,      "7937H",
+       NRD7914PBPT,    NRD7914PTRK,    NRD7914PBPT * NRD7914PTRK,
+       rd7914P_sizes,  RD7914CTID,     0,      "7914CT",
+       NRD7945ABPT,    NRD7945ATRK,    NRD7945ABPT * NRD7945ATRK,
+       rd7945A_sizes,  RD7946AID,      0,      "7946A",
+       NRD9122SBPT,    NRD9122STRK,    NRD9122SBPT * NRD9122STRK,
+       rd9122S_sizes,  RD9134LID,      1,      "9122D",
+       NRD7957BBPT,    NRD7957BTRK,    NRD7957BBPT * NRD7957BTRK,
+       rd7957B_sizes,  RD7957BID,      0,      "7957B",
+       NRD7958BBPT,    NRD7958BTRK,    NRD7958BBPT * NRD7958BTRK,
+       rd7958B_sizes,  RD7958BID,      0,      "7958B",
+       NRD7959BBPT,    NRD7959BTRK,    NRD7959BBPT * NRD7959BTRK,
+       rd7959B_sizes,  RD7959BID,      0,      "7959B",
+};
+int nrdinfo = sizeof(rdinfo) / sizeof(rdinfo[0]);
+
+struct buf rdtab[NRD];
+struct buf rdbuf[NRD];
+
+#define        rdunit(x)       ((minor(x) >> 3) & 0xf)
+#define rdpart(x)      (minor(x) & 0x7)
+#define        rdpunit(x)      ((x) & 7)
+#define        b_cylin         b_resid
+#define        RDRETRY         5
+#define RDWAITC                1       /* min time for timeout in seconds */
+
+rdinit(hd)
+       register struct hp_device *hd;
+{
+       register struct rd_softc *rs = &rd_softc[hd->hp_unit];
+
+       rs->sc_hd = hd;
+       rs->sc_punit = rdpunit(hd->hp_flags);
+       rs->sc_type = rdident(rs, hd);
+       if (rs->sc_type < 0)
+               return(0);
+       rs->sc_dq.dq_ctlr = hd->hp_ctlr;
+       rs->sc_dq.dq_unit = hd->hp_unit;
+       rs->sc_dq.dq_slave = hd->hp_slave;
+       rs->sc_dq.dq_driver = &rddriver;
+       rs->sc_info = &rdinfo[rs->sc_type];
+       rs->sc_flags = RDF_ALIVE;
+       return(1);
+}
+
+rdident(rs, hd)
+       struct rd_softc *rs;
+       struct hp_device *hd;
+{
+       struct rd_describe desc;
+       u_char stat, cmd[3];
+       int unit, lunit;
+       char name[7];
+       register int ctlr, slave, id, i;
+
+       ctlr = hd->hp_ctlr;
+       slave = hd->hp_slave;
+       unit = rs->sc_punit;
+       lunit = hd->hp_unit;
+
+       /*
+        * Grab device id and make sure:
+        * 1. It is a CS80 device.
+        * 2. It is one of the types we support.
+        * 3. If it is a 7946, we are accessing the disk unit (0)
+        */
+       id = hpibid(ctlr, slave);
+       if ((id & 0x200) == 0)
+               return(-1);
+       for (i = 0; i < nrdinfo; i++)
+               if (id == rdinfo[i].hwid)
+                       break;
+       if (i == nrdinfo || unit > rdinfo[i].maxunum)
+               return(-1);
+       id = i;
+
+       /*
+        * Reset drive and collect device description.
+        * Don't really use the description info right now but
+        * might come in handy in the future (for disk labels).
+        */
+       rdreset(rs, hd);
+       cmd[0] = C_SUNIT(unit);
+       cmd[1] = C_SVOL(0);
+       cmd[2] = C_DESC;
+       hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd));
+       hpibrecv(ctlr, slave, C_EXEC, &desc, 37);
+       hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
+       bzero(name, sizeof(name));
+       if (!stat) {
+               register int n = desc.d_name;
+               for (i = 5; i >= 0; i--) {
+                       name[i] = (n & 0xf) + '0';
+                       n >>= 4;
+               }
+       }
+#ifdef DEBUG
+       if (rddebug & RDB_IDENT) {
+               printf("rd%d: name: %x ('%s')\n",
+                      lunit, desc.d_name, name);
+               printf("  iuw %x, maxxfr %d, ctype %d\n",
+                      desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype);
+               printf("  utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n",
+                      desc.d_utype, desc.d_sectsize,
+                      desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime);
+               printf("  avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n",
+                      desc.d_uavexfr, desc.d_retry, desc.d_access,
+                      desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte);
+               printf("  maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n",
+                      desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect,
+                      desc.d_maxvsectl, desc.d_interleave);
+       }
+#endif
+       /*
+        * Take care of a couple of anomolies:
+        * 1. 7945A and 7946A both return same HW id
+        * 2. 9122S and 9134D both return same HW id
+        * 3. 9122D and 9134L both return same HW id
+        */
+       switch (rdinfo[id].hwid) {
+       case RD7946AID:
+               if (bcmp(name, "079450", 6) == 0)
+                       id = RD7945A;
+               else
+                       id = RD7946A;
+               break;
+
+       case RD9134LID:
+               if (bcmp(name, "091340", 6) == 0)
+                       id = RD9134L;
+               else
+                       id = RD9122D;
+               break;
+
+       case RD9134DID:
+               if (bcmp(name, "091220", 6) == 0)
+                       id = RD9122S;
+               else
+                       id = RD9134D;
+               break;
+       }
+       printf("rd%d: %s\n", lunit, rdinfo[id].desc);
+       return(id);
+}
+
+rdreset(rs, hd)
+       register struct rd_softc *rs;
+       register struct hp_device *hd;
+{
+       u_char stat;
+
+       rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit);
+       rs->sc_clear.c_cmd = C_CLEAR;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear,
+               sizeof(rs->sc_clear));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+       rs->sc_src.c_unit = C_SUNIT(RDCTLR);
+       rs->sc_src.c_nop = C_NOP;
+       rs->sc_src.c_cmd = C_SREL;
+       rs->sc_src.c_param = C_REL;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src,
+               sizeof(rs->sc_src));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+       rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit);
+       rs->sc_ssmc.c_cmd = C_SSM;
+       rs->sc_ssmc.c_refm = REF_MASK;
+       rs->sc_ssmc.c_fefm = FEF_MASK;
+       rs->sc_ssmc.c_aefm = AEF_MASK;
+       rs->sc_ssmc.c_iefm = IEF_MASK;
+       hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc,
+               sizeof(rs->sc_ssmc));
+       hpibswait(hd->hp_ctlr, hd->hp_slave);
+       hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
+#ifdef DEBUG
+       rdstats[hd->hp_unit].rdresets++;
+#endif
+}
+
+/*ARGSUSED*/
+rdopen(dev, flags)
+       dev_t dev;
+{
+       register int unit = rdunit(dev);
+       register struct rd_softc *rs = &rd_softc[unit];
+
+       if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0)
+               return(ENXIO);
+       if (rs->sc_hd->hp_dk >= 0)
+       dk_wpms[rs->sc_hd->hp_dk] = 60 * rs->sc_info->nbpt * DEV_BSIZE / 2;
+       return(0);
+}
+
+rdstrategy(bp)
+       register struct buf *bp;
+{
+       register int part = rdpart(bp->b_dev);
+       register int unit = rdunit(bp->b_dev);
+       register int bn, sz;
+       register struct rd_softc *rs = &rd_softc[unit];
+       register struct buf *dp = &rdtab[unit];
+       int s;
+
+#ifdef DEBUG
+       if (rddebug & RDB_FOLLOW)
+               printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n",
+                      bp, bp->b_dev, bp->b_blkno, bp->b_bcount,
+                      (bp->b_flags & B_READ) ? 'R' : 'W');
+#endif
+       bn = bp->b_blkno;
+       sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT;
+       if (bn < 0 || bn + sz > rs->sc_info->sizes[part].nblocks) {
+               if (bn == rs->sc_info->sizes[part].nblocks) {
+                       bp->b_resid = bp->b_bcount;
+                       goto done;
+               }
+               bp->b_error = EINVAL;
+               goto bad;
+       }
+       bp->b_cylin = bn / rs->sc_info->nbpc + rs->sc_info->sizes[part].cyloff;
+       s = splbio();
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               dp->b_active = 1;
+               rdustart(unit);
+       }
+       splx(s);
+       return;
+bad:
+       bp->b_flags |= B_ERROR;
+done:
+       biodone(bp);
+}
+
+/*
+ * Called from timeout() when handling maintenance releases
+ */
+rdrestart(unit)
+       int unit;
+{
+       int s = splbio();
+       rdustart(unit);
+       splx(s);
+}
+
+rdustart(unit)
+       register int unit;
+{
+       register struct buf *bp;
+       register struct rd_softc *rs = &rd_softc[unit];
+
+       bp = rdtab[unit].b_actf;
+       rs->sc_addr = bp->b_un.b_addr;
+       rs->sc_resid = bp->b_bcount;
+       if (hpibreq(&rs->sc_dq))
+               rdstart(unit);
+}
+
+rdstart(unit)
+       register int unit;
+{
+       register struct rd_softc *rs = &rd_softc[unit];
+       register struct buf *bp = rdtab[unit].b_actf;
+       register struct hp_device *hp = rs->sc_hd;
+       register int part;
+
+again:
+#ifdef DEBUG
+       if (rddebug & RDB_FOLLOW)
+               printf("rdstart(%d): bp %x, %c\n", unit, bp,
+                      (bp->b_flags & B_READ) ? 'R' : 'W');
+#endif
+       part = rdpart(bp->b_dev);
+       rs->sc_flags |= RDF_SEEK;
+       rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit);
+       rs->sc_ioc.c_volume = C_SVOL(0);
+       rs->sc_ioc.c_saddr = C_SADDR;
+       rs->sc_ioc.c_hiaddr = 0;
+       rs->sc_ioc.c_addr = RDBTOS(bp->b_blkno + rs->sc_info->nbpc *
+               rs->sc_info->sizes[part].cyloff);
+       rs->sc_ioc.c_nop2 = C_NOP;
+       rs->sc_ioc.c_slen = C_SLEN;
+       rs->sc_ioc.c_len = rs->sc_resid;
+       rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE;
+#ifdef DEBUG
+       if (rddebug & RDB_IO)
+               printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n",
+                      hp->hp_ctlr, hp->hp_slave, C_CMD,
+                      &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2);
+#endif
+       if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit,
+                    sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) {
+               if (hp->hp_dk >= 0) {
+                       dk_busy |= 1 << hp->hp_dk;
+                       dk_seek[hp->hp_dk]++;
+               }
+#ifdef DEBUG
+               if (rddebug & RDB_IO)
+                       printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr);
+#endif
+               hpibawait(hp->hp_ctlr);
+               return;
+       }
+       /*
+        * Experience has shown that the hpibwait in this hpibsend will
+        * occasionally timeout.  It appears to occur mostly on old 7914
+        * drives with full maintenance tracks.  We should probably
+        * integrate this with the backoff code in rderror.
+        */
+#ifdef DEBUG
+       if (rddebug & RDB_ERROR)
+               printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n",
+                      unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr,
+                      bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt);
+       rdstats[unit].rdretries++;
+#endif
+       rs->sc_flags &= ~RDF_SEEK;
+       rdreset(rs, hp);
+       if (rdtab[unit].b_errcnt++ < RDRETRY)
+               goto again;
+       printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n",
+              unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr,
+              bp->b_blkno, rs->sc_resid);
+       rdtab[unit].b_errcnt = 0;
+       rdtab[unit].b_actf = bp->b_actf;
+       bp->b_flags |= B_ERROR;
+       bp->b_error = EIO;
+       bp->b_resid = 0;
+       biodone(bp);
+       hpibfree(&rs->sc_dq);
+       bp = rdtab[unit].b_actf;
+       if (bp == NULL) {
+               rdtab[unit].b_active = 0;
+               return;
+       }
+       rs->sc_addr = bp->b_un.b_addr;
+       rs->sc_resid = bp->b_bcount;
+       if (hpibreq(&rs->sc_dq))
+               goto again;
+}
+
+rdgo(unit)
+       register int unit;
+{
+       register struct rd_softc *rs = &rd_softc[unit];
+       register struct hp_device *hp = rs->sc_hd;
+       struct buf *bp = rdtab[unit].b_actf;
+
+       if (hp->hp_dk >= 0) {
+               dk_busy |= 1 << hp->hp_dk;
+               dk_xfer[hp->hp_dk]++;
+               dk_wds[hp->hp_dk] += rs->sc_resid >> 6;
+       }
+       hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC,
+              rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ);
+}
+
+rdintr(unit)
+       register int unit;
+{
+       register struct rd_softc *rs = &rd_softc[unit];
+       register struct buf *bp = rdtab[unit].b_actf;
+       register struct hp_device *hp = rs->sc_hd;
+       u_char stat = 13;       /* in case hpibrecv fails */
+       int restart;
+       
+#ifdef DEBUG
+       if (rddebug & RDB_FOLLOW)
+               printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp,
+                      (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags);
+       if (bp == NULL) {
+               printf("rd%d: bp == NULL\n", unit);
+               return;
+       }
+#endif
+       if (hp->hp_dk >= 0)
+               dk_busy &= ~(1 << hp->hp_dk);
+       if (rs->sc_flags & RDF_SEEK) {
+               rs->sc_flags &= ~RDF_SEEK;
+               if (hpibustart(hp->hp_ctlr))
+                       rdgo(unit);
+               return;
+       }
+       if ((rs->sc_flags & RDF_SWAIT) == 0) {
+#ifdef DEBUG
+               rdstats[unit].rdpolltries++;
+#endif
+               if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) {
+#ifdef DEBUG
+                       rdstats[unit].rdpollwaits++;
+#endif
+                       if (hp->hp_dk >= 0)
+                               dk_busy |= 1 << hp->hp_dk;
+                       rs->sc_flags |= RDF_SWAIT;
+                       hpibawait(hp->hp_ctlr);
+                       return;
+               }
+       } else
+               rs->sc_flags &= ~RDF_SWAIT;
+       if (!hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1) || stat) {
+#ifdef DEBUG
+               if (rddebug & RDB_ERROR)
+                       printf("rdintr: recv failed or bad stat %d\n", stat);
+#endif
+               restart = rderror(unit);
+#ifdef DEBUG
+               rdstats[unit].rdretries++;
+#endif
+               if (rdtab[unit].b_errcnt++ < RDRETRY) {
+                       if (restart)
+                               rdstart(unit);
+                       return;
+               }
+               bp->b_flags |= B_ERROR;
+               bp->b_error = EIO;
+       }
+       rdtab[unit].b_errcnt = 0;
+       rdtab[unit].b_actf = bp->b_actf;
+       bp->b_resid = 0;
+       biodone(bp);
+       hpibfree(&rs->sc_dq);
+       if (rdtab[unit].b_actf)
+               rdustart(unit);
+       else
+               rdtab[unit].b_active = 0;
+}
+
+rdstatus(rs)
+       register struct rd_softc *rs;
+{
+       register int c, s;
+       u_char stat;
+       int rv;
+
+       c = rs->sc_hd->hp_ctlr;
+       s = rs->sc_hd->hp_slave;
+       rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit);
+       rs->sc_rsc.c_sram = C_SRAM;
+       rs->sc_rsc.c_ram = C_RAM;
+       rs->sc_rsc.c_cmd = C_STATUS;
+       bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat));
+       rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc));
+       if (rv != sizeof(rs->sc_rsc)) {
+#ifdef DEBUG
+               if (rddebug & RDB_STATUS)
+                       printf("rdstatus: send C_CMD failed %d != %d\n",
+                              rv, sizeof(rs->sc_rsc));
+#endif
+               return(1);
+       }
+       rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat));
+       if (rv != sizeof(rs->sc_stat)) {
+#ifdef DEBUG
+               if (rddebug & RDB_STATUS)
+                       printf("rdstatus: send C_EXEC failed %d != %d\n",
+                              rv, sizeof(rs->sc_stat));
+#endif
+               return(1);
+       }
+       rv = hpibrecv(c, s, C_QSTAT, &stat, 1);
+       if (rv != 1 || stat) {
+#ifdef DEBUG
+               if (rddebug & RDB_STATUS)
+                       printf("rdstatus: recv failed %d or bad stat %d\n",
+                              rv, stat);
+#endif
+               return(1);
+       }
+       return(0);
+}
+
+/*
+ * Deal with errors.
+ * Returns 1 if request should be restarted,
+ * 0 if we should just quietly give up.
+ */
+rderror(unit)
+       int unit;
+{
+       struct rd_softc *rs = &rd_softc[unit];
+       register struct rd_stat *sp;
+       struct buf *bp;
+       daddr_t bn, pbn;
+
+       if (rdstatus(rs)) {
+#ifdef DEBUG
+               printf("rd%d: couldn't get status\n", unit);
+#endif
+               rdreset(rs, rs->sc_hd);
+               return(1);
+       }
+       sp = &rs->sc_stat;
+       if (sp->c_fef & FEF_REXMT)
+               return(1);
+       if (sp->c_fef & FEF_PF) {
+               rdreset(rs, rs->sc_hd);
+               return(1);
+       }
+       /*
+        * Unit requests release for internal maintenance.
+        * We just delay awhile and try again later.  Use expontially
+        * increasing backoff ala ethernet drivers since we don't really
+        * know how long the maintenance will take.  With RDWAITC and
+        * RDRETRY as defined, the range is 1 to 32 seconds.
+        */
+       if (sp->c_fef & FEF_IMR) {
+               extern int hz;
+               int rdtimo = RDWAITC << rdtab[unit].b_errcnt;
+#ifdef DEBUG
+               printf("rd%d: internal maintenance, %d second timeout\n",
+                      unit, rdtimo);
+               rdstats[unit].rdtimeouts++;
+#endif
+               hpibfree(&rs->sc_dq);
+               timeout(rdrestart, unit, rdtimo*hz);
+               return(0);
+       }
+       bp = rdtab[unit].b_actf;
+       /*
+        * First conjure up the block number at which the error occured.
+        * Note that not all errors report a block number, in that case
+        * we just use b_blkno.
+        */
+       pbn = RDSTOB(rs->sc_info->nbpc *
+                    rs->sc_info->sizes[rdpart(bp->b_dev)].cyloff);
+       if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) ||
+           (sp->c_ief & IEF_RRMASK)) {
+               bn = pbn + bp->b_blkno;
+               pbn = bp->b_blkno;
+       } else {
+               bn = RDSTOB(sp->c_blk);
+               pbn = bn - pbn;
+       }
+       /*
+        * Now output a generic message suitable for badsect.
+        * Note that we don't use harderr cuz it just prints
+        * out b_blkno which is just the beginning block number
+        * of the transfer, not necessary where the error occured.
+        */
+       printf("rd%d%c: hard error sn%d\n",
+              rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn);
+       /*
+        * Now report the status as returned by the hardware with
+        * attempt at interpretation (unless debugging).
+        */
+       printf("rd%d %s error:",
+              unit, (bp->b_flags & B_READ) ? "read" : "write");
+#ifdef DEBUG
+       if (rddebug & RDB_ERROR) {
+               /* status info */
+               printf("\n    volume: %d, unit: %d\n",
+                      (sp->c_vu>>4)&0xF, sp->c_vu&0xF);
+               rdprinterr("reject", sp->c_ref, err_reject);
+               rdprinterr("fault", sp->c_fef, err_fault);
+               rdprinterr("access", sp->c_aef, err_access);
+               rdprinterr("info", sp->c_ief, err_info);
+               printf("    block: %d, P1-P10: ", bn);
+               printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8));
+               printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8));
+               printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4));
+               /* command */
+               printf("    ioc: ");
+               printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8));
+               printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4));
+               printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8));
+               printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4));
+               printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8));
+               printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4));
+               return(1);
+       }
+#endif
+       printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n",
+              (sp->c_vu>>4)&0xF, sp->c_vu&0xF,
+              sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief);
+       printf("P1-P10: ");
+       printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8));
+       printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8));
+       printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4));
+       return(1);
+}
+
+rdread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = rdunit(dev);
+
+       return(physio(rdstrategy, &rdbuf[unit], dev, B_READ, minphys, uio));
+}
+
+rdwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = rdunit(dev);
+
+       return(physio(rdstrategy, &rdbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+/*ARGSUSED*/
+rdioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       caddr_t data;
+       int flag;
+{
+       return(EINVAL);
+}
+
+rdsize(dev)
+       dev_t dev;
+{
+       register int unit = rdunit(dev);
+       register struct rd_softc *rs = &rd_softc[unit];
+
+       if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0)
+               return(-1);
+       return(rs->sc_info->sizes[rdpart(dev)].nblocks);
+}
+
+#ifdef DEBUG
+rdprinterr(str, err, tab)
+       char *str;
+       short err;
+       char *tab[];
+{
+       register int i;
+       int printed;
+
+       if (err == 0)
+               return;
+       printf("    %s error field:", str, err);
+       printed = 0;
+       for (i = 0; i < 16; i++)
+               if (err & (0x8000 >> i))
+                       printf("%s%s", printed++ ? " + " : " ", tab[i]);
+       printf("\n");
+}
+#endif
+
+#include "machine/pte.h"
+#include "machine/vmparam.h"
+#include "../h/vmmac.h"
+
+/*
+ * Non-interrupt driven, non-dma dump routine.
+ */
+rddump(dev)
+       dev_t dev;
+{
+       int part = rdpart(dev);
+       int unit = rdunit(dev);
+       register struct rd_softc *rs = &rd_softc[unit];
+       register struct hp_device *hp = rs->sc_hd;
+       register daddr_t baddr;
+       register int maddr;
+       register int pages, i;
+       char stat;
+       extern int lowram, dumpsize;
+
+       pages = dumpsize;
+#ifdef DEBUG
+       if (rddebug & RDB_DUMP)
+               printf("rddump(%x): u %d p %d dumplo %d ram %x pmem %d\n",
+                      dev, unit, part, dumplo, lowram, ctod(pages));
+#endif
+       /* is drive ok? */
+       if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0)
+               return (ENXIO);
+       /* HPIB idle? */
+       if (!hpibreq(&rs->sc_dq)) {
+#ifdef DEBUG
+               /* is this a safe thing to do?? */
+               hpibreset(hp->hp_ctlr);
+               rdreset(rs, rs->sc_hd);
+               printf("[ drive %d reset ] ", unit);
+#else
+               return (EFAULT);
+#endif
+       }
+       /* dump parameters in range? */
+       if (dumplo < 0 || dumplo >= rs->sc_info->sizes[part].nblocks)
+               return (EINVAL);
+       if (dumplo + ctod(pages) > rs->sc_info->sizes[part].nblocks)
+               pages = dtoc(rs->sc_info->sizes[part].nblocks - dumplo);
+       maddr = lowram;
+       baddr = dumplo + rs->sc_info->nbpc * rs->sc_info->sizes[part].cyloff;
+#ifdef DEBUG
+       if (rddebug & RDB_DUMP)
+               printf("rddump: dumping %d pages from %x to disk block %d\n",
+                      pages, maddr, baddr);
+#endif
+       for (i = 0; i < pages; i++) {
+#ifdef DEBUG
+#define NPGMB  (1024*1024/NBPG)
+               /* print out how many Mbs we have dumped */
+               if (i && (i % NPGMB) == 0)
+                       printf("%d ", i / NPGMB);
+#undef NPBMG
+#endif
+               rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit);
+               rs->sc_ioc.c_volume = C_SVOL(0);
+               rs->sc_ioc.c_saddr = C_SADDR;
+               rs->sc_ioc.c_hiaddr = 0;
+               rs->sc_ioc.c_addr = RDBTOS(baddr);
+               rs->sc_ioc.c_nop2 = C_NOP;
+               rs->sc_ioc.c_slen = C_SLEN;
+               rs->sc_ioc.c_len = NBPG;
+               rs->sc_ioc.c_cmd = C_WRITE;
+               hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD,
+                        &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2);
+               if (hpibswait(hp->hp_ctlr, hp->hp_slave)) {
+#ifdef DEBUG
+                       if (rddebug & RDB_DUMP)
+                               printf("rddump: IOC wait timeout\n");
+#endif
+                       return (EIO);
+               }
+               mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V);
+               hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG);
+               if (hpibswait(hp->hp_ctlr, hp->hp_slave)) {
+#ifdef DEBUG
+                       if (rddebug & RDB_DUMP)
+                               printf("rddump: write wait timeout\n");
+#endif
+               }
+               hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1);
+               if (stat) {
+#ifdef DEBUG
+                       if (rddebug & RDB_DUMP)
+                               printf("rddump: write failed, status %x\n",
+                                      stat);
+#endif
+                       return (EIO);
+               }
+               maddr += NBPG;
+               baddr += ctod(1);
+       }
+       return (0);
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/rdreg.h b/usr/src/sys/hp300/dev/rdreg.h
new file mode 100644 (file)
index 0000000..323aa7a
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: rdreg.h 1.14 89/02/27$
+ *
+ *     @(#)rdreg.h     7.1 (Berkeley) %G%
+ */
+
+struct rd_iocmd {
+       char    c_pad;
+       char    c_unit;
+       char    c_volume;
+       char    c_saddr;
+       short   c_hiaddr;
+       long    c_addr;
+       char    c_nop2;
+       char    c_slen;
+       long    c_len;
+       char    c_cmd;
+       char    c_pad2;
+};
+
+struct rd_rscmd {
+       char    c_unit;
+       char    c_sram;
+       char    c_ram;
+       char    c_cmd;
+};
+
+struct rd_stat {
+       char    c_vu;
+       char    c_pend;
+       short   c_ref;
+       short   c_fef;
+       short   c_aef;
+       short   c_ief;
+       union {
+               char cu_raw[10];
+               struct {
+                       short   cu_msw;
+                       long    cu_lsl;
+               } cu_sva;
+               struct {
+                       long    cu_cyhd;
+                       short   cu_sect;
+               } cu_tva;
+       } c_pf;
+};
+#define c_raw  c_pf.cu_raw
+#define c_blk  c_pf.cu_sva.cu_lsl      /* for now */
+#define c_tva  c_pf.cu_tva
+
+struct rd_ssmcmd {
+       char    c_unit;
+       char    c_cmd;
+       short   c_refm;
+       short   c_fefm;
+       short   c_aefm;
+       short   c_iefm;
+};
+
+struct rd_srcmd {
+       char    c_unit;
+       char    c_nop;
+       char    c_cmd;
+       char    c_param;
+};
+
+struct rd_clearcmd {
+       char    c_unit;
+       char    c_cmd;
+};
+
+struct rd_describe {
+       u_int   d_iuw:16,       /* controller: installed unit word */
+               d_cmaxxfr:16,   /* controller: max transfer rate (Kb) */
+               d_ctype:8,      /* controller: controller type */
+               d_utype:8,      /* unit: unit type */
+               d_name:24,      /* unit: name (6 BCD digits) */
+               d_sectsize:16,  /* unit: # of bytes per block (sector) */
+               d_blkbuf:8,     /* unit: # of blocks which can be buffered */
+               d_burstsize:8,  /* unit: recommended burst size */
+               d_blocktime:16, /* unit: block time (u-sec) */
+               d_uavexfr:16,   /* unit: average transfer rate (Kb) */
+               d_retry:16,     /* unit: optimal retry time (1/100-sec) */
+               d_access:16,    /* unit: access time param (1/100-sec) */
+               d_maxint:8,     /* unit: maximum interleave */
+               d_fvbyte:8,     /* unit: fixed volume byte */
+               d_rvbyte:8,     /* unit: removeable volume byte */
+               d_maxcyl:24,    /* volume: maximum cylinder */
+               d_maxhead:8,    /* volume: maximum head */
+               d_maxsect:16,   /* volume: maximum sector on track */
+               d_maxvsecth:16, /* volume: maximum sector on volume (MSW) */
+               d_maxvsectl:32, /* volume: maximum sector on volume (LSWs) */
+               d_interleave:8; /* volume: current interleave */
+ };
+
+/* indicies into rdinfo -- order is arbitrary */
+#define        RD7945A         0
+#define        RD9134D         1
+#define        RD9122S         2
+#define        RD7912P         3
+#define        RD7914P         4
+#define        RD7958A         5
+#define RD7957A                6
+#define        RD7933H         7
+#define        RD9134L         8
+#define        RD7936H         9
+#define        RD7937H         10
+#define RD7914CT       11
+#define RD7946A                12
+#define RD9122D                13
+#define RD7957B                14
+#define RD7958B                15
+#define RD7959B                16
+
+/* HW ids */
+#define        RD7946AID       0x220   /* also 7945A */
+#define        RD9134DID       0x221   /* also 9122S */
+#define        RD9134LID       0x222   /* also 9122D */
+#define        RD7912PID       0x209
+#define RD7914CTID     0x20A
+#define        RD7914PID       0x20B
+#define        RD7958AID       0x22B
+#define RD7957AID      0x22A
+#define        RD7933HID       0x212
+#define        RD7936HID       0x213   /* just guessing -- as of yet unknown */
+#define        RD7937HID       0x214
+#define RD7957BID      0x22C   /* another guess based on 7958B */
+#define RD7958BID      0x22D
+#define RD7959BID      0x22E   /* another guess based on 7958B */
+
+#define        NRD7945ABPT     (32 >> (DEV_BSHIFT-8))
+#define        NRD7945ATRK     7
+#define        NRD9134DBPT     (32 >> (DEV_BSHIFT-8))
+#define        NRD9134DTRK     6
+#define        NRD9122SBPT     (16 >> (DEV_BSHIFT-8))
+#define        NRD9122STRK     2
+#define        NRD7912PBPT     (64 >> (DEV_BSHIFT-8))
+#define        NRD7912PTRK     7
+#define        NRD7914PBPT     (64 >> (DEV_BSHIFT-8))
+#define        NRD7914PTRK     7
+#define        NRD7933HBPT     (92 >> (DEV_BSHIFT-8))
+#define        NRD7933HTRK     13
+#define        NRD9134LBPT     (32 >> (DEV_BSHIFT-8))
+#define        NRD9134LTRK     5
+
+/*
+ * Several HP drives have an odd number of 256 byte sectors per track.
+ * This makes it rather difficult to break them into 512 and 1024 byte blocks.
+ * So...we just do like HPUX and don't bother to respect hardware track/head
+ * boundries -- we just mold the disk so that we use the entire capacity.
+ * HPUX also sometimes doen't abide by cylinder boundries, we attempt to
+ * whenever possible.
+ *
+ * DISK                REAL (256 BPS)          HPUX (1024 BPS)         BSD (512 BPS)
+ *             SPT x HD x CYL          SPT x HD x CYL          SPT x HD x CYL
+ * -----       ---------------         ---------------         --------------
+ * 7936:       123 x  7 x 1396         25 x  7 x 1716          123 x  7 x  698
+ * 7937:       123 x 13 x 1396         25 x 16 x 1395          123 x 13 x  698
+ *
+ * 7957A:       63 x  5 x 1013         11 x  7 x 1036           22 x  7 x 1036
+ * 7958A:       63 x  8 x 1013         21 x  6 x 1013           36 x  7 x 1013
+ *
+ * 7957B:       63 x  4 x 1269          9 x  7 x 1269           18 x  7 x 1269
+ * 7958B:       63 x  6 x 1572         21 x  9 x  786           42 x  9 x  786
+ * 7959B:       63 x 12 x 1572         21 x  9 x 1572           42 x  9 x 1572
+ */
+#if DEV_BSIZE == 512
+#      define  NRD7936HBPT     123
+#      define  NRD7936HTRK     7
+#      define  NRD7937HBPT     123
+#      define  NRD7937HTRK     13
+#      define  NRD7957ABPT     22
+#      define  NRD7957ATRK     7
+#      define  NRD7958ABPT     36
+#      define  NRD7958ATRK     7
+#      define  NRD7957BBPT     18
+#      define  NRD7957BTRK     7
+#      define  NRD7958BBPT     42
+#      define  NRD7958BTRK     9
+#      define  NRD7959BBPT     42
+#      define  NRD7959BTRK     9
+#endif
+#if DEV_BSIZE == 1024
+#      define  NRD7957ABPT     11
+#      define  NRD7957ATRK     7
+#      define  NRD7958ABPT     21
+#      define  NRD7958ATRK     6
+#      define  NRD7957BBPT     9
+#      define  NRD7957BTRK     7
+#      define  NRD7958BBPT     21
+#      define  NRD7958BTRK     9
+#      define  NRD7959BBPT     21
+#      define  NRD7959BTRK     9
+#endif
+
+/* controller "unit" number */
+#define        RDCTLR          15
+
+/* convert 512 byte count into DEV_BSIZE count */
+#define RDSZ(x)                ((x) >> (DEV_BSHIFT-9))
+
+/* convert block number into sector number and back */
+#define        RDBTOS(x)       ((x) << (DEV_BSHIFT-8))
+#define RDSTOB(x)      ((x) >> (DEV_BSHIFT-8))
+
+/* extract cyl/head/sect info from three-vector address */
+#define RDCYL(tva)     ((u_long)(tva).cu_cyhd >> 8)
+#define RDHEAD(tva)    ((tva).cu_cyhd & 0xFF)
+#define RDSECT(tva)    ((tva).cu_sect)
+
+#define        REF_MASK        0x0
+#define        FEF_MASK        0x0
+#define        AEF_MASK        0x0
+#define        IEF_MASK        0xF970
+
+#define FEF_CU         0x4000  /* cross-unit */
+#define FEF_DR         0x0080  /* diagnostic result */
+#define FEF_IMR                0x0008  /* internal maintenance release */
+#define        FEF_PF          0x0002  /* power fail */
+#define        FEF_REXMT       0x0001  /* retransmit */
+#define AEF_UD         0x0040  /* unrecoverable data */
+#define IEF_RRMASK     0xe000  /* request release bits */
+#define IEF_MD         0x0020  /* marginal data */
+#define IEF_RD         0x0010  /* recoverable data */
+
+#define        C_READ          0x00
+#define        C_RAM           0x00    /* single vector (i.e. sector number) */
+#define        C_WRITE         0x02
+#define        C_CLEAR         0x08
+#define        C_STATUS        0x0d
+#define        C_SADDR         0x10
+#define        C_SLEN          0x18
+#define        C_SUNIT(x)      (0x20 | (x))
+#define C_SVOL(x)      (0x40 | (x))
+#define        C_NOP           0x34
+#define C_DESC         0x35
+#define        C_SREL          0x3b
+#define        C_SSM           0x3e
+#define        C_SRAM          0x48
+#define        C_REL           0x140
+
+#define        C_CMD           0x05
+#define        C_EXEC          0x0e
+#define        C_QSTAT         0x10
+#define        C_TCMD          0x12
diff --git a/usr/src/sys/hp300/dev/scsi.c b/usr/src/sys/hp300/dev/scsi.c
new file mode 100644 (file)
index 0000000..2be64e5
--- /dev/null
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)scsi.c      7.1 (Berkeley) %G%
+ */
+
+/*
+ * HP9000/3xx 98658 SCSI host adaptor driver.
+ */
+#include "scsi.h"
+#if NSCSI > 0
+
+#ifndef lint
+static char rcsid[] = "$Header: scsi.c,v 1.3 90/01/06 04:56:50 van Exp $";
+#endif
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "device.h"
+#include "scsivar.h"
+#include "scsireg.h"
+#include "dmavar.h"
+
+#include "machine/cpu.h"
+#include "machine/isr.h"
+
+extern void isrlink();
+extern void printf();
+extern void _insque();
+extern void _remque();
+extern void bzero();
+
+int    scsiinit(), scsigo(), scsiintr(), scsixfer();
+void   scsistart(), scsidone(), scsifree(), scsireset();
+struct driver scsidriver = {
+       scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr,
+       (int (*)())scsidone,
+};
+
+struct scsi_softc scsi_softc[NSCSI];
+struct isr scsi_isr[NSCSI];
+
+int scsi_cmd_wait = 512;       /* microsec wait per step of 'immediate' cmds */
+int scsi_data_wait = 512;      /* wait per data in/out step */
+int scsi_nosync = 1;           /* inhibit sync xfers if 1 */
+
+#ifdef DEBUG
+int    scsi_debug = 0;
+#define WAITHIST
+#endif
+
+#ifdef WAITHIST
+#define MAXWAIT        2048
+u_int  ixstart_wait[MAXWAIT+2];
+u_int  ixin_wait[MAXWAIT+2];
+u_int  ixout_wait[MAXWAIT+2];
+u_int  mxin_wait[MAXWAIT+2];
+u_int  cxin_wait[MAXWAIT+2];
+u_int  fxfr_wait[MAXWAIT+2];
+u_int  sgo_wait[MAXWAIT+2];
+#define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]);
+#else
+#define HIST(h,w)
+#endif
+
+#define        b_cylin         b_resid
+
+static void
+scsiabort(hs, hd, where)
+       register struct scsi_softc *hs;
+       volatile register struct scsidevice *hd;
+       char *where;
+{
+       int len;
+       u_char junk;
+
+       printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",
+               hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts,
+               hd->scsi_ints);
+
+       hd->scsi_ints = hd->scsi_ints;
+       hd->scsi_csr = 0;
+       if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
+               /* no longer connected to scsi target */
+               return;
+
+       /* get the number of bytes remaining in current xfer + fudge */
+       len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
+
+       /* for that many bus cycles, try to send an abort msg */
+       for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
+               hd->scsi_scmd = SCMD_SET_ATN;
+               while ((hd->scsi_psns & PSNS_REQ) == 0) {
+                       if (! (hd->scsi_ssts & SSTS_INITIATOR))
+                               goto out;
+                       DELAY(1);
+               }
+               if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
+                       hd->scsi_scmd = SCMD_RST_ATN;
+               hd->scsi_pctl = hd->scsi_psns & PHASE;
+               if (hd->scsi_psns & PHASE_IO) {
+                       /* one of the input phases - read & discard a byte */
+                       hd->scsi_scmd = SCMD_SET_ACK;
+                       if (hd->scsi_tmod == 0)
+                               while (hd->scsi_psns & PSNS_REQ)
+                                       DELAY(1);
+                       junk = hd->scsi_temp;
+               } else {
+                       /* one of the output phases - send an abort msg */
+                       hd->scsi_temp = MSG_ABORT;
+                       hd->scsi_scmd = SCMD_SET_ACK;
+                       if (hd->scsi_tmod == 0)
+                               while (hd->scsi_psns & PSNS_REQ)
+                                       DELAY(1);
+               }
+               hd->scsi_scmd = SCMD_RST_ACK;
+       }
+out:
+       /*
+        * Either the abort was successful & the bus is disconnected or
+        * the device didn't listen.  If the latter, announce the problem.
+        * Either way, reset the card & the SPC.
+        */
+       if (len < 0 && hs)
+               printf("scsi%d: abort failed.  phase=0x%x, ssts=0x%x\n",
+                       hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
+
+       if (! ((junk = hd->scsi_ints) & INTS_RESEL)) {
+               hd->scsi_sctl |= SCTL_CTRLRST;
+               DELAY(1);
+               hd->scsi_sctl &=~ SCTL_CTRLRST;
+               hd->scsi_hconf = 0;
+               hd->scsi_ints = hd->scsi_ints;
+       }
+}
+
+int
+scsiinit(hc)
+       register struct hp_ctlr *hc;
+{
+       register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];
+       register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr;
+       
+       if ((hd->scsi_id & ID_MASK) != SCSI_ID)
+               return(0);
+       hc->hp_ipl = SCSI_IPL(hd->scsi_csr);
+       hs->sc_hc = hc;
+       hs->sc_dq.dq_unit = hc->hp_unit;
+       hs->sc_dq.dq_driver = &scsidriver;
+       hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
+       scsi_isr[hc->hp_unit].isr_intr = scsiintr;
+       scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl;
+       scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;
+       isrlink(&scsi_isr[hc->hp_unit]);
+       scsireset(hc->hp_unit);
+       return(1);
+}
+
+void
+scsireset(unit)
+       register int unit;
+{
+       register struct scsi_softc *hs = &scsi_softc[unit];
+       volatile register struct scsidevice *hd =
+                               (struct scsidevice *)hs->sc_hc->hp_addr;
+       u_int i;
+
+       if (hs->sc_flags & SCSI_ALIVE)
+               scsiabort(hs, hd, "reset");
+               
+       printf("scsi%d: ", unit);
+
+       hd->scsi_id = 0xFF;
+       DELAY(100);
+       /*
+        * Disable interrupts then reset the FUJI chip.
+        */
+       hd->scsi_csr  = 0;
+       hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
+       hd->scsi_scmd = 0;
+       hd->scsi_tmod = 0;
+       hd->scsi_pctl = 0;
+       hd->scsi_temp = 0;
+       hd->scsi_tch  = 0;
+       hd->scsi_tcm  = 0;
+       hd->scsi_tcl  = 0;
+       hd->scsi_ints = 0;
+
+       if ((hd->scsi_id & ID_WORD_DMA) == 0) {
+               hs->sc_flags |= SCSI_DMA32;
+               printf("32 bit dma, ");
+       }
+
+       /* Determine Max Synchronous Transfer Rate */
+       if (scsi_nosync)
+               i = 3;
+       else
+               i = SCSI_SYNC_XFER(hd->scsi_hconf);
+       switch (i) {
+               case 0:
+                       hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */
+                       printf("250ns sync");
+                       break;
+               case 1:
+                       hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */
+                       printf("375ns sync");
+                       break;
+               case 2:
+                       hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */
+                       printf("500ns sync");
+                       break;
+               case 3:
+                       hs->sc_sync = 0;
+                       printf("async");
+                       break;
+               }
+
+       /*
+        * Configure the FUJI chip with its SCSI address, all
+        * interrupts enabled & appropriate parity.
+        */
+       i = (~hd->scsi_hconf) & 0x7;
+       hs->sc_scsi_addr = 1 << i;
+       hd->scsi_bdid = i;
+       if (hd->scsi_hconf & HCONF_PARITY)
+               hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
+                               SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
+                               SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
+       else {
+               hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
+                               SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
+                               SCTL_INTR_ENAB;
+               printf(", no parity");
+       }
+       hd->scsi_sctl &=~ SCTL_DISABLE;
+
+       printf(", scsi id %d\n", i);
+       hs->sc_flags |= SCSI_ALIVE;
+}
+
+static void
+scsierror(hs, hd, ints)
+       register struct scsi_softc *hs;
+       volatile register struct scsidevice *hd;
+       u_char ints;
+{
+       int unit = hs->sc_hc->hp_unit;
+       char *sep = "";
+
+       printf("scsi%d: ", unit);
+       if (ints & INTS_RST) {
+               DELAY(100);
+               if (hd->scsi_hconf & HCONF_SD)
+                       printf("spurious RST interrupt");
+               else
+                       printf("hardware error - check fuse");
+               sep = ", ";
+       }
+       if ((ints & INTS_HARD_ERR) || hd->scsi_serr) {
+               if (hd->scsi_serr & SERR_SCSI_PAR) {
+                       printf("%sparity err", sep);
+                       sep = ", ";
+               }
+               if (hd->scsi_serr & SERR_SPC_PAR) {
+                       printf("%sSPC parity err", sep);
+                       sep = ", ";
+               }
+               if (hd->scsi_serr & SERR_TC_PAR) {
+                       printf("%sTC parity err", sep);
+                       sep = ", ";
+               }
+               if (hd->scsi_serr & SERR_PHASE_ERR) {
+                       printf("%sphase err", sep);
+                       sep = ", ";
+               }
+               if (hd->scsi_serr & SERR_SHORT_XFR) {
+                       printf("%ssync short transfer err", sep);
+                       sep = ", ";
+               }
+               if (hd->scsi_serr & SERR_OFFSET) {
+                       printf("%ssync offset error", sep);
+                       sep = ", ";
+               }
+       }
+       if (ints & INTS_TIMEOUT)
+               printf("%sSPC select timeout error", sep);
+       if (ints & INTS_SRV_REQ)
+               printf("%sspurious SRV_REQ interrupt", sep);
+       if (ints & INTS_CMD_DONE)
+               printf("%sspurious CMD_DONE interrupt", sep);
+       if (ints & INTS_DISCON)
+               printf("%sspurious disconnect interrupt", sep);
+       if (ints & INTS_RESEL)
+               printf("%sspurious reselect interrupt", sep);
+       if (ints & INTS_SEL)
+               printf("%sspurious select interrupt", sep);
+       printf("\n");
+}
+
+static int
+issue_select(hd, target, our_addr)
+       volatile register struct scsidevice *hd;
+       u_char target, our_addr;
+{
+       if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
+               return (1);
+
+       if (hd->scsi_ints & INTS_DISCON)
+               hd->scsi_ints = INTS_DISCON;
+
+       hd->scsi_pctl = 0;
+       hd->scsi_temp = (1 << target) | our_addr;
+       /* select timeout is hardcoded to 2ms */
+       hd->scsi_tch = 0;
+       hd->scsi_tcm = 32;
+       hd->scsi_tcl = 4;
+
+       hd->scsi_scmd = SCMD_SELECT;
+       return (0);
+}
+
+static int
+wait_for_select(hd)
+       volatile register struct scsidevice *hd;
+{
+       u_char ints;
+
+       while ((ints = hd->scsi_ints) == 0)
+               DELAY(1);
+       hd->scsi_ints = ints;
+       return (!(hd->scsi_ssts & SSTS_INITIATOR));
+}
+
+static int
+ixfer_start(hd, len, phase, wait)
+       volatile register struct scsidevice *hd;
+       int len;
+       u_char phase;
+       register int wait;
+{
+
+       hd->scsi_tch = len >> 16;
+       hd->scsi_tcm = len >> 8;
+       hd->scsi_tcl = len;
+       hd->scsi_pctl = phase;
+       hd->scsi_tmod = 0; /*XXX*/
+       hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
+
+       /* wait for xfer to start or svc_req interrupt */
+       while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
+               if (hd->scsi_ints || --wait < 0) {
+#ifdef DEBUG
+                       if (scsi_debug)
+                               printf("ixfer_start fail: i%x, w%d\n",
+                                      hd->scsi_ints, wait);
+#endif
+                       HIST(ixstart_wait, wait)
+                       return (0);
+               }
+               DELAY(1);
+       }
+       HIST(ixstart_wait, wait)
+       return (1);
+}
+
+static int
+ixfer_out(hd, len, buf)
+       volatile register struct scsidevice *hd;
+       int len;
+       register u_char *buf;
+{
+       register int wait = scsi_data_wait;
+
+       for (; len > 0; --len) {
+               while (hd->scsi_ssts & SSTS_DREG_FULL) {
+                       if (hd->scsi_ints || --wait < 0) {
+#ifdef DEBUG
+                               if (scsi_debug)
+                                       printf("ixfer_out fail: l%d i%x w%d\n",
+                                              len, hd->scsi_ints, wait);
+#endif
+                               HIST(ixout_wait, wait)
+                               return (len);
+                       }
+                       DELAY(1);
+               }
+               hd->scsi_dreg = *buf++;
+       }
+       HIST(ixout_wait, wait)
+       return (0);
+}
+
+static void
+ixfer_in(hd, len, buf)
+       volatile register struct scsidevice *hd;
+       int len;
+       register u_char *buf;
+{
+       register int wait = scsi_data_wait;
+
+       for (; len > 0; --len) {
+               while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
+                       if (hd->scsi_ints || --wait < 0) {
+                               while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
+                                       *buf++ = hd->scsi_dreg;
+                                       --len;
+                               }
+#ifdef DEBUG
+                               if (scsi_debug)
+                                       printf("ixfer_in fail: l%d i%x w%d\n",
+                                              len, hd->scsi_ints, wait);
+#endif
+                               HIST(ixin_wait, wait)
+                               return;
+                       }
+                       DELAY(1);
+               }
+               *buf++ = hd->scsi_dreg;
+       }
+       HIST(ixin_wait, wait)
+}
+
+static int
+mxfer_in(hd, len, buf, phase)
+       volatile register struct scsidevice *hd;
+       register int len;
+       register u_char *buf;
+       register u_char phase;
+{
+       register int wait = scsi_cmd_wait;
+       register int i;
+
+       hd->scsi_tmod = 0;
+       for (i = 0; i < len; ++i) {
+               /*
+                * wait for the request line (which says the target
+                * wants to give us data).  If the phase changes while
+                * we're waiting, we're done.
+                */
+               while ((hd->scsi_psns & PSNS_REQ) == 0) {
+                       if (--wait < 0) {
+                               HIST(mxin_wait, wait)
+                               return (-1);
+                       }
+                       if ((hd->scsi_psns & PHASE) != phase ||
+                           (hd->scsi_ssts & SSTS_INITIATOR) == 0)
+                               goto out;
+
+                       DELAY(1);
+               }
+               /*
+                * set ack (which says we're ready for the data, wait for
+                * req to go away (target says data is available), grab the
+                * data, then reset ack (say we've got the data).
+                */
+               hd->scsi_pctl = phase;
+               hd->scsi_scmd = SCMD_SET_ACK;
+               while (hd->scsi_psns & PSNS_REQ) {
+                       if (--wait < 0) {
+                               HIST(mxin_wait, wait)
+                               return (-2);
+                       }
+                       DELAY(1);
+               }
+               *buf++ = hd->scsi_temp;
+               hd->scsi_scmd = SCMD_RST_ACK;
+               if (hd->scsi_psns & PSNS_ATN)
+                       hd->scsi_scmd = SCMD_RST_ATN;
+       }
+out:
+       HIST(mxin_wait, wait)
+       return (i);
+}
+
+/*
+ * SCSI 'immediate' command:  issue a command to some SCSI device
+ * and get back an 'immediate' response (i.e., do programmed xfer
+ * to get the response data).  'cbuf' is a buffer containing a scsi
+ * command of length clen bytes.  'buf' is a buffer of length 'len'
+ * bytes for data.  The transfer direction is determined by the device
+ * (i.e., by the scsi bus data xfer phase).  If 'len' is zero, the
+ * command must supply no data.  'xferphase' is the bus phase the
+ * caller expects to happen after the command is issued.  It should
+ * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE.
+ */
+static int
+scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
+       struct scsi_softc *hs;
+       int target;
+       u_char *cbuf;
+       int clen;
+       u_char *buf;
+       int len;
+       u_char xferphase;
+{
+       volatile register struct scsidevice *hd =
+                               (struct scsidevice *)hs->sc_hc->hp_addr;
+       u_char phase, ints;
+       register int wait;
+
+       /* select the SCSI bus (it's an error if bus isn't free) */
+       if (issue_select(hd, target, hs->sc_scsi_addr))
+               return (-1);
+       if (wait_for_select(hd))
+               return (-1);
+       /*
+        * Wait for a phase change (or error) then let the device
+        * sequence us through the various SCSI phases.
+        */
+       hs->sc_stat[0] = 0xff;
+       hs->sc_msg[0] = 0xff;
+       phase = CMD_PHASE;
+       while (1) {
+               wait = scsi_cmd_wait;
+               switch (phase) {
+
+               case CMD_PHASE:
+                       if (ixfer_start(hd, clen, phase, wait))
+                               if (ixfer_out(hd, clen, cbuf))
+                                       goto abort;
+                       phase = xferphase;
+                       break;
+
+               case DATA_IN_PHASE:
+                       if (len <= 0)
+                               goto abort;
+                       wait = scsi_data_wait;
+                       if (ixfer_start(hd, len, phase, wait) ||
+                           !(hd->scsi_ssts & SSTS_DREG_EMPTY))
+                               ixfer_in(hd, len, buf);
+                       phase = STATUS_PHASE;
+                       break;
+
+               case DATA_OUT_PHASE:
+                       if (len <= 0)
+                               goto abort;
+                       wait = scsi_data_wait;
+                       if (ixfer_start(hd, len, phase, wait)) {
+                               if (ixfer_out(hd, len, buf))
+                                       goto abort;
+                       }
+                       phase = STATUS_PHASE;
+                       break;
+
+               case STATUS_PHASE:
+                       wait = scsi_data_wait;
+                       if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
+                           !(hd->scsi_ssts & SSTS_DREG_EMPTY))
+                               ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat);
+                       phase = MESG_IN_PHASE;
+                       break;
+
+               case MESG_IN_PHASE:
+                       if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
+                           !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
+                               ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
+                               hd->scsi_scmd = SCMD_RST_ACK;
+                       }
+                       phase = BUS_FREE_PHASE;
+                       break;
+
+               case BUS_FREE_PHASE:
+                       goto out;
+
+               default:
+                       printf("scsi%d: unexpected phase %d in icmd from %d\n",
+                               hs->sc_hc->hp_unit, phase, target);
+                       goto abort;
+               }
+               /* wait for last command to complete */
+               while ((ints = hd->scsi_ints) == 0) {
+                       if (--wait < 0) {
+                               HIST(cxin_wait, wait)
+                               goto abort;
+                       }
+                       DELAY(1);
+               }
+               HIST(cxin_wait, wait)
+               hd->scsi_ints = ints;
+               if (ints & INTS_SRV_REQ)
+                       phase = hd->scsi_psns & PHASE;
+               else if (ints & INTS_DISCON)
+                       goto out;
+               else if ((ints & INTS_CMD_DONE) == 0) {
+                       scsierror(hs, hd, ints);
+                       goto abort;
+               }
+       }
+abort:
+       scsiabort(hs, hd, "icmd");
+out:
+       return (hs->sc_stat[0]);
+}
+
+/*
+ * Finish SCSI xfer command:  After the completion interrupt from
+ * a read/write operation, sequence through the final phases in
+ * programmed i/o.  This routine is a lot like scsiicmd except we
+ * skip (and don't allow) the select, cmd out and data in/out phases.
+ */
+static void
+finishxfer(hs, hd, target)
+       struct scsi_softc *hs;
+       volatile register struct scsidevice *hd;
+       int target;
+{
+       u_char phase, ints;
+
+       /*
+        * We specified padding xfer so we ended with either a phase
+        * change interrupt (normal case) or an error interrupt (handled
+        * elsewhere).  Reset the board dma logic then try to get the
+        * completion status & command done msg.  The reset confuses
+        * the SPC REQ/ACK logic so we have to do any status/msg input
+        * operations via 'manual xfer'.
+        */
+       if (hd->scsi_ssts & SSTS_BUSY) {
+               int wait = scsi_cmd_wait;
+
+               /* wait for dma operation to finish */
+               while (hd->scsi_ssts & SSTS_BUSY) {
+                       if (--wait < 0) {
+#ifdef DEBUG
+                               if (scsi_debug)
+                                       printf("finishxfer fail: ssts %x\n",
+                                              hd->scsi_ssts);
+#endif
+                               HIST(fxfr_wait, wait)
+                               goto abort;
+                       }
+               }
+               HIST(fxfr_wait, wait)
+       }
+       hd->scsi_scmd |= SCMD_PROG_XFR;
+       hd->scsi_sctl |= SCTL_CTRLRST;
+       DELAY(1);
+       hd->scsi_sctl &=~ SCTL_CTRLRST;
+       hd->scsi_hconf = 0;
+       hs->sc_stat[0] = 0xff;
+       hs->sc_msg[0] = 0xff;
+       hd->scsi_csr = 0;
+       hd->scsi_ints = ints = hd->scsi_ints;
+       while (1) {
+               phase = hd->scsi_psns & PHASE;
+               switch (phase) {
+
+               case STATUS_PHASE:
+                       if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat,
+                                    phase) <= 0)
+                               goto abort;
+                       break;
+
+               case MESG_IN_PHASE:
+                       if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg,
+                                    phase) < 0)
+                               goto abort;
+                       break;
+
+               case BUS_FREE_PHASE:
+                       return;
+
+               default:
+                       printf("scsi%d: unexpected phase %d in finishxfer from %d\n",
+                               hs->sc_hc->hp_unit, phase, target);
+                       goto abort;
+               }
+               if (ints = hd->scsi_ints) {
+                       hd->scsi_ints = ints;
+                       if (ints & INTS_DISCON)
+                               return;
+                       else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) {
+                               scsierror(hs, hd, ints);
+                               break;
+                       }
+               }
+               if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
+                       return;
+       }
+abort:
+       scsiabort(hs, hd, "finishxfer");
+       hs->sc_stat[0] = 0xfe;
+}
+
+int
+scsi_test_unit_rdy(ctlr, slave, unit)
+       int ctlr, slave, unit;
+{
+       register struct scsi_softc *hs = &scsi_softc[ctlr];
+       static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
+
+       cdb.lun = unit;
+       return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
+                        STATUS_PHASE));
+}
+
+int
+scsi_request_sense(ctlr, slave, unit, buf, len)
+       int ctlr, slave, unit;
+       u_char *buf;
+       unsigned len;
+{
+       register struct scsi_softc *hs = &scsi_softc[ctlr];
+       static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
+
+       cdb.lun = unit;
+       cdb.len = len;
+       return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
+}
+
+int
+scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd)
+       int ctlr, slave, unit;
+       struct scsi_fmt_cdb *cdb;
+       u_char *buf;
+       unsigned len;
+{
+       register struct scsi_softc *hs = &scsi_softc[ctlr];
+
+       cdb->cdb[1] |= unit << 5;
+       return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len,
+                        rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE));
+}
+
+/*
+ * The following routines are test-and-transfer i/o versions of read/write
+ * for things like reading disk labels and writing core dumps.  The
+ * routine scsigo should be used for normal data transfers, NOT these
+ * routines.
+ */
+int
+scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift)
+       int ctlr, slave, unit;
+       u_char *buf;
+       u_int len;
+       daddr_t blk;
+       int bshift;
+{
+       register struct scsi_softc *hs = &scsi_softc[ctlr];
+       struct scsi_cdb10 cdb;
+       int stat;
+       int old_wait = scsi_data_wait;
+
+       scsi_data_wait = 300000;
+       bzero(&cdb, sizeof(cdb));
+       cdb.cmd = CMD_READ_EXT;
+       cdb.lun = unit;
+       blk >>= bshift;
+       cdb.lbah = blk >> 24;
+       cdb.lbahm = blk >> 16;
+       cdb.lbalm = blk >> 8;
+       cdb.lbal = blk;
+       cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
+       cdb.lenl = len >> (DEV_BSHIFT + bshift);
+       stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE);
+       scsi_data_wait = old_wait;
+       return (stat);
+}
+
+int
+scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift)
+       int ctlr, slave, unit;
+       u_char *buf;
+       u_int len;
+       daddr_t blk;
+       int bshift;
+{
+       register struct scsi_softc *hs = &scsi_softc[ctlr];
+       struct scsi_cdb10 cdb;
+       int stat;
+       int old_wait = scsi_data_wait;
+
+       scsi_data_wait = 300000;
+
+       bzero(&cdb, sizeof(cdb));
+       cdb.cmd = CMD_WRITE_EXT;
+       cdb.lun = unit;
+       blk >>= bshift;
+       cdb.lbah = blk >> 24;
+       cdb.lbahm = blk >> 16;
+       cdb.lbalm = blk >> 8;
+       cdb.lbal = blk;
+       cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
+       cdb.lenl = len >> (DEV_BSHIFT + bshift);
+       stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE);
+       scsi_data_wait = old_wait;
+       return (stat);
+}
+
+
+int
+scsireq(dq)
+       register struct devqueue *dq;
+{
+       register struct devqueue *hq;
+
+       hq = &scsi_softc[dq->dq_ctlr].sc_sq;
+       insque(dq, hq->dq_back);
+       if (dq->dq_back == hq)
+               return(1);
+       return(0);
+}
+
+int
+scsiustart(unit)
+       int unit;
+{
+       register struct scsi_softc *hs = &scsi_softc[unit];
+
+       hs->sc_dq.dq_ctlr = DMA0 | DMA1;
+       if (dmareq(&hs->sc_dq))
+               return(1);
+       return(0);
+}
+
+void
+scsistart(unit)
+       int unit;
+{
+       register struct devqueue *dq;
+       
+       dq = scsi_softc[unit].sc_sq.dq_forw;
+       (dq->dq_driver->d_go)(dq->dq_unit);
+}
+
+int
+scsigo(ctlr, slave, unit, bp, cdb, pad)
+       int ctlr, slave, unit;
+       struct buf *bp;
+       struct scsi_fmt_cdb *cdb;
+       int pad;
+{
+       register struct scsi_softc *hs = &scsi_softc[ctlr];
+       volatile register struct scsidevice *hd =
+                               (struct scsidevice *)hs->sc_hc->hp_addr;
+       int i, dmaflags;
+       u_char phase, ints, cmd;
+
+       cdb->cdb[1] |= unit << 5;
+
+       /* select the SCSI bus (it's an error if bus isn't free) */
+       if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) {
+               dmafree(&hs->sc_dq);
+               return (1);
+       }
+       /*
+        * Wait for a phase change (or error) then let the device
+        * sequence us through command phase (we may have to take
+        * a msg in/out before doing the command).  If the disk has
+        * to do a seek, it may be a long time until we get a change
+        * to data phase so, in the absense of an explicit phase
+        * change, we assume data phase will be coming up and tell
+        * the SPC to start a transfer whenever it does.  We'll get
+        * a service required interrupt later if this assumption is
+        * wrong.  Otherwise we'll get a service required int when
+        * the transfer changes to status phase.
+        */
+       phase = CMD_PHASE;
+       while (1) {
+               register int wait = scsi_cmd_wait;
+
+               switch (phase) {
+
+               case CMD_PHASE:
+                       if (ixfer_start(hd, cdb->len, phase, wait))
+                               if (ixfer_out(hd, cdb->len, cdb->cdb))
+                                       goto abort;
+                       break;
+
+               case MESG_IN_PHASE:
+                       if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)||
+                           !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
+                               ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
+                               hd->scsi_scmd = SCMD_RST_ACK;
+                       }
+                       phase = BUS_FREE_PHASE;
+                       break;
+
+               case DATA_IN_PHASE:
+               case DATA_OUT_PHASE:
+                       goto out;
+
+               default:
+                       printf("scsi%d: unexpected phase %d in go from %d\n",
+                               hs->sc_hc->hp_unit, phase, slave);
+                       goto abort;
+               }
+               while ((ints = hd->scsi_ints) == 0) {
+                       if (--wait < 0) {
+                               HIST(sgo_wait, wait)
+                               goto abort;
+                       }
+                       DELAY(1);
+               }
+               HIST(sgo_wait, wait)
+               hd->scsi_ints = ints;
+               if (ints & INTS_SRV_REQ)
+                       phase = hd->scsi_psns & PHASE;
+               else if (ints & INTS_CMD_DONE)
+                       goto out;
+               else {
+                       scsierror(hs, hd, ints);
+                       goto abort;
+               }
+       }
+out:
+       /*
+        * Reset the card dma logic, setup the dma channel then
+        * get the dio part of the card set for a dma xfer.
+        */
+       hd->scsi_hconf = 0;
+       cmd = CSR_IE | (CSR_DE0 << hs->sc_dq.dq_ctlr);
+       dmaflags = DMAGO_NOINT;
+       if (bp->b_flags & B_READ)
+               dmaflags |= DMAGO_READ;
+       if ((hs->sc_flags & SCSI_DMA32) &&
+           ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) {
+               cmd |= CSR_DMA32;
+               dmaflags |= DMAGO_LWORD;
+       } else
+               dmaflags |= DMAGO_WORD;
+       dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags);
+
+       if (bp->b_flags & B_READ) {
+               cmd |= CSR_DMAIN;
+               phase = DATA_IN_PHASE;
+       } else
+               phase = DATA_OUT_PHASE;
+       hd->scsi_csr = cmd;
+       /*
+        * Setup the SPC for the transfer.  We don't want to take
+        * first a command complete then a service required interrupt
+        * at the end of the transfer so we try to disable the cmd
+        * complete by setting the transfer counter to more bytes
+        * than we expect.  (XXX - This strategy may have to be
+        * modified to deal with devices that return variable length
+        * blocks, e.g., some tape drives.)
+        */
+       cmd = SCMD_XFR;
+       i = (unsigned)bp->b_bcount;
+       if (pad) {
+               cmd |= SCMD_PAD;
+               /*
+                * XXX - If we don't do this, the last 2 or 4 bytes
+                * (depending on word/lword DMA) of a read get trashed.
+                * It looks like it is necessary for the DMA to complete
+                * before the SPC goes into "pad mode"???  Note: if we
+                * also do this on a write, the request never completes.
+                */
+               if (bp->b_flags & B_READ)
+                       i += 2;
+#ifdef DEBUG
+               hs->sc_flags |= SCSI_PAD;
+               if (i & 1)
+                       printf("scsi%d: odd byte count: %d bytes @ %d\n",
+                               ctlr, i, bp->b_cylin);
+#endif
+       } else
+               i += 4;
+       hd->scsi_tch = i >> 16;
+       hd->scsi_tcm = i >> 8;
+       hd->scsi_tcl = i;
+       hd->scsi_pctl = phase;
+       hd->scsi_tmod = 0;
+       hd->scsi_scmd = cmd;
+       hs->sc_flags |= SCSI_IO;
+       return (0);
+abort:
+       scsiabort(hs, hd, "go");
+       dmafree(&hs->sc_dq);
+       return (1);
+}
+
+void
+scsidone(unit)
+       register int unit;
+{
+       volatile register struct scsidevice *hd =
+                       (struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr;
+
+       /* dma operation is done -- turn off card dma */
+       hd->scsi_csr &=~ (CSR_DE1|CSR_DE0);
+}
+
+int
+scsiintr(unit)
+       register int unit;
+{
+       register struct scsi_softc *hs = &scsi_softc[unit];
+       volatile register struct scsidevice *hd =
+                               (struct scsidevice *)hs->sc_hc->hp_addr;
+       register u_char ints;
+       register struct devqueue *dq;
+
+       if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR))
+               return (0);
+
+       ints = hd->scsi_ints;
+       if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) {
+               /*
+                * this should be the normal i/o completion case.
+                * get the status & cmd complete msg then let the
+                * device driver look at what happened.
+                */
+#ifdef DEBUG
+               int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) |
+                         hd->scsi_tcl;
+               if (!(hs->sc_flags & SCSI_PAD))
+                       len -= 4;
+               if (len)
+                       printf("scsi%d: transfer length error %d\n", unit, len);
+               hs->sc_flags &=~ SCSI_PAD;
+#endif
+               dq = hs->sc_sq.dq_forw;
+               finishxfer(hs, hd, dq->dq_unit);
+               hs->sc_flags &=~ SCSI_IO;
+               dmafree(&hs->sc_dq);
+               (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);
+       } else {
+               /* Something unexpected happened -- deal with it. */
+               hd->scsi_ints = ints;
+               hd->scsi_csr = 0;
+               scsierror(hs, hd, ints);
+               scsiabort(hs, hd, "intr");
+               if (hs->sc_flags & SCSI_IO) {
+                       hs->sc_flags &=~ SCSI_IO;
+                       dmafree(&hs->sc_dq);
+                       dq = hs->sc_sq.dq_forw;
+                       (dq->dq_driver->d_intr)(dq->dq_unit, -1);
+               }
+       }
+       return(1);
+}
+
+void
+scsifree(dq)
+       register struct devqueue *dq;
+{
+       register struct devqueue *hq;
+
+       hq = &scsi_softc[dq->dq_ctlr].sc_sq;
+       remque(dq);
+       if ((dq = hq->dq_forw) != hq)
+               (dq->dq_driver->d_start)(dq->dq_unit);
+}
+#endif
diff --git a/usr/src/sys/hp300/dev/scsireg.h b/usr/src/sys/hp300/dev/scsireg.h
new file mode 100644 (file)
index 0000000..75eb718
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)scsireg.h   7.1 (Berkeley) %G%
+ */
+
+/*
+ * HP 98265A SCSI Interface Hardware Description.
+ */
+
+struct scsidevice {
+       u_char  p0,  scsi_id;
+#define                        ID_MASK         0x1f
+#define                        SCSI_ID         0x07
+#define                        ID_WORD_DMA     0x20
+       u_char  p2,  scsi_csr;
+#define                        CSR_IE          0x80
+#define                        CSR_IR          0x40
+#define                        SCSI_IPL(csr)   ((((csr)>>4)&3)+3)
+#define                        CSR_DMA32       0x08
+#define                        CSR_DMAIN       0x04
+#define                        CSR_DE1         0x02
+#define                        CSR_DE0         0x01
+       u_char  p4,  scsi_wrap;
+#define                        WRAP_REQ        0x80
+#define                        WRAP_ACK        0x40
+#define                        WRAP_BSY        0x08
+#define                        WRAP_MSG        0x04
+#define                        WRAP_CD         0x02
+#define                        WRAP_IO         0x01
+       u_char  p6,  scsi_hconf;
+#define                        HCONF_TP        0x80
+#define                        SCSI_SYNC_XFER(hconf) (((hconf)>>5)&3)
+#define                        HCONF_SD        0x10
+#define                        HCONF_PARITY    0x08
+       u_char  p8[24];
+       u_char  p32, scsi_bdid;
+       u_char  p34, scsi_sctl;
+#define                        SCTL_DISABLE    0x80
+#define                        SCTL_CTRLRST    0x40
+#define                        SCTL_DIAG       0x20
+#define                        SCTL_ABRT_ENAB  0x10
+#define                        SCTL_PARITY_ENAB 0x08
+#define                        SCTL_SEL_ENAB   0x04
+#define                        SCTL_RESEL_ENAB 0x02
+#define                        SCTL_INTR_ENAB  0x01
+       u_char  p36, scsi_scmd;
+#define                        SCMD_RST        0x10
+#define                        SCMD_ICPT_XFR   0x08
+#define                        SCMD_PROG_XFR   0x04
+#define                        SCMD_PAD        0x01    /* if initiator */
+#define                        SCMD_PERR_STOP  0x01    /* if target */
+                       /* command codes */
+#define                        SCMD_BUS_REL    0x00
+#define                        SCMD_SELECT     0x20
+#define                        SCMD_RST_ATN    0x40
+#define                        SCMD_SET_ATN    0x60
+#define                        SCMD_XFR        0x80
+#define                        SCMD_XFR_PAUSE  0xa0
+#define                        SCMD_RST_ACK    0xc0
+#define                        SCMD_SET_ACK    0xe0
+       u_char  p38, scsi_tmod;
+#define                        TMOD_SYNC       0x80
+       u_char  p40, scsi_ints;
+#define                        INTS_SEL        0x80
+#define                        INTS_RESEL      0x40
+#define                        INTS_DISCON     0x20
+#define                        INTS_CMD_DONE   0x10
+#define                        INTS_SRV_REQ    0x08
+#define                        INTS_TIMEOUT    0x04
+#define                        INTS_HARD_ERR   0x02
+#define                        INTS_RST        0x01
+       u_char  p42, scsi_psns;
+#define                        PSNS_REQ        0x80
+#define                        PSNS_ACK        0x40
+#define                        PSNS_ATN        0x20
+#define                        PSNS_SEL        0x10
+#define                        PSNS_BSY        0x08
+       u_char  p44, scsi_ssts;
+#define                        SSTS_INITIATOR  0x80
+#define                        SSTS_TARGET     0x40
+#define                        SSTS_BUSY       0x20
+#define                        SSTS_XFR        0x10
+#define                        SSTS_ACTIVE     (SSTS_INITIATOR|SSTS_XFR)
+#define                        SSTS_RST        0x08
+#define                        SSTS_TCZERO     0x04
+#define                        SSTS_DREG_FULL  0x02
+#define                        SSTS_DREG_EMPTY 0x01
+       u_char  p46, scsi_serr;
+#define                        SERR_SCSI_PAR   0x80
+#define                        SERR_SPC_PAR    0x40
+#define                        SERR_TC_PAR     0x08
+#define                        SERR_PHASE_ERR  0x04
+#define                        SERR_SHORT_XFR  0x02
+#define                        SERR_OFFSET     0x01
+       u_char  p48, scsi_pctl;
+#define                        PCTL_BFINT_ENAB 0x80
+       u_char  p50, scsi_mbc;
+       u_char  p52, scsi_dreg;
+       u_char  p54, scsi_temp;
+       u_char  p56, scsi_tch;
+       u_char  p58, scsi_tcm;
+       u_char  p60, scsi_tcl;
+       u_char  p62, scsi_exbf;
+};
+
+/* psns/pctl phase lines as bits */
+#define        PHASE_MSG       0x04
+#define        PHASE_CD        0x02            /* =1 if 'command' */
+#define        PHASE_IO        0x01            /* =1 if data inbound */
+/* Phase lines as values */
+#define        PHASE           0x07            /* mask for psns/pctl phase */
+#define        DATA_OUT_PHASE  0x00
+#define        DATA_IN_PHASE   0x01
+#define        CMD_PHASE       0x02
+#define        STATUS_PHASE    0x03
+#define        BUS_FREE_PHASE  0x04
+#define        ARB_SEL_PHASE   0x05    /* Fuji chip combines arbitration with sel. */
+#define        MESG_OUT_PHASE  0x06
+#define        MESG_IN_PHASE   0x07
+
+/* SCSI Messages */
+
+#define        MSG_CMD_COMPLETE        0x00
+#define MSG_EXT_MESSAGE                0x01
+#define        MSG_SAVE_DATA_PTR       0x02
+#define        MSG_RESTORE_PTR         0x03
+#define        MSG_DISCONNECT          0x04
+#define        MSG_INIT_DETECT_ERROR   0x05
+#define        MSG_ABORT               0x06
+#define        MSG_REJECT              0x07
+#define        MSG_NOOP                0x08
+#define        MSG_PARITY_ERROR        0x09
+#define        MSG_BUS_DEVICE_RESET    0x0C
+#define        MSG_IDENTIFY            0x80
+#define        MSG_IDENTIFY_DR         0xc0    /* (disconnect/reconnect allowed) */
+#define        MSG_SYNC_REQ            0x01
+
+/* SCSI Commands */
+
+#define CMD_TEST_UNIT_READY    0x00
+#define CMD_REQUEST_SENSE      0x03
+#define        CMD_INQUIRY             0x12
+#define CMD_SEND_DIAGNOSTIC    0x1D
+
+#define CMD_FORMAT_UNIT                0x04
+#define CMD_REASSIGN_BLOCKS    0x07
+#define CMD_READ               0x08
+#define CMD_WRITE              0x0A
+#define CMD_MODE_SELECT                0x15
+#define CMD_RELEASE_UNIT       0x17
+#define CMD_MODE_SENSE         0x1A
+#define CMD_SEND_DIAG          0x1D
+#define CMD_READ_CAPACITY      0x25
+#define CMD_READ_EXT           0x28
+#define CMD_WRITE_EXT          0x2A
+#define CMD_READ_DEFECT_DATA   0x37
+#define                SD_MANUFAC_DEFECTS      0x14000000
+#define                SD_GROWN_DEFECTS        0x0c000000
+#define CMD_READ_BUFFER                0x3B
+#define CMD_WRITE_BUFFER       0x3C
+#define CMD_READ_FULL          0xF0
+#define CMD_MEDIA_TEST         0xF1
+#define CMD_ACCESS_LOG         0xF2
+#define CMD_WRITE_FULL         0xFC
+#define CMD_MANAGE_PRIMARY     0xFD
+#define CMD_EXECUTE_DATA       0xFE
+
+/* SCSI status bits */
+
+#define        STS_CHECKCOND   0x02    /* Check Condition (ie., read sense) */
+#define        STS_CONDMET     0x04    /* Condition Met (ie., search worked) */
+#define        STS_BUSY        0x08
+#define        STS_INTERMED    0x10    /* Intermediate status sent */
+#define        STS_EXT         0x80    /* Extended status valid */
+
+/* command descriptor blocks */
+
+struct scsi_cdb6 {
+       u_char  cmd;            /* command code */
+       u_char  lun:  3,        /* logical unit on ctlr */
+               lbah: 5;        /* msb of read/write logical block addr */
+       u_char  lbam;           /* middle byte of l.b.a. */
+       u_char  lbal;           /* lsb of l.b.a. */
+       u_char  len;            /* transfer length */
+       u_char  xtra;
+};
+
+struct scsi_cdb10 {
+       u_char  cmd;            /* command code */
+       u_char  lun: 3,         /* logical unit on ctlr */
+                  : 4,
+               rel: 1;         /* l.b.a. is relative addr if =1 */
+       u_char  lbah;           /* msb of read/write logical block addr */
+       u_char  lbahm;          /* high middle byte of l.b.a. */
+       u_char  lbalm;          /* low middle byte of l.b.a. */
+       u_char  lbal;           /* lsb of l.b.a. */
+       u_char  reserved;
+       u_char  lenh;           /* msb transfer length */
+       u_char  lenl;           /* lsb transfer length */
+       u_char  xtra;
+};
+
+/* basic sense data */
+
+struct scsi_sense {
+       u_char  valid: 1,       /* l.b.a. is valid */
+               class: 3,
+               code:  4;
+       u_char  vu:    4,       /* vendor unique */
+               lbah:  4;
+       u_char  lbam;
+       u_char  lbal;
+};
+
+struct scsi_xsense {
+       u_char  valid: 1,       /* l.b.a. is valid */
+               class: 3,
+               code:  4;
+       u_char  segment;
+       u_char  filemark: 1,
+               eom:      1,
+               ili:      1,    /* illegal length indicator */
+               rsvd:     1,
+               key:      4;
+       u_char  info1;
+       u_char  info2;
+       u_char  info3;
+       u_char  info4;
+       u_char  len;            /* additional sense length */
+};
+
+/* inquiry data */
+struct scsi_inquiry {
+       u_char  type;
+       u_char  qual;
+       u_char  version;
+       u_char  rsvd;
+       u_char  len;
+       char    class[3];
+       char    vendor_id[8];
+       char    product_id[16];
+       char    rev[4];
+};
+
+struct scsi_format_parms {             /* physical BFI format */
+       u_short reserved;
+       u_short list_len;
+       struct defect {
+               unsigned cyl  : 24;
+               unsigned head : 8;
+               long    bytes_from_index;
+       } defect[127];
+} format_parms;
+
+struct scsi_reassign_parms {
+       u_short reserved;
+       u_short list_len;       /* length in bytes of defects only */
+       struct new_defect {
+               unsigned lba;   /* logical block address */
+       } new_defect[2];
+} reassign_parms;
+
+struct scsi_modesel_hdr {
+       u_char  rsvd1;
+       u_char  media_type;
+       u_char  rsvd2;
+       u_char  block_desc_len;
+       u_int   density         : 8;
+       u_int   number_blocks   :24;
+       u_int   rsvd3           : 8;
+       u_int   block_length    :24;
+}; 
+
+struct scsi_modesense_hdr {
+       u_char  len;
+       u_char  media_type;
+       u_char  wp    : 1;
+       u_char  rsvd1 : 7;
+       u_char  block_desc_len;
+       u_int   density         : 8;
+       u_int   number_blocks   :24;
+       u_int   rsvd2           : 8;
+       u_int   block_length    :24;
+}; 
+
+/*
+ * Mode Select / Mode sense "pages"
+ */
+
+/*
+ * Page One - Error Recovery Parameters 
+ */
+struct scsi_err_recovery {
+       u_char  page_savable    : 1;    /* save parameters */
+       u_char  reserved        : 1;
+       u_char  page_code       : 6;    /* = 0x01 */
+       u_char  page_length;            /* = 6 */
+       u_char  awre            : 1;    /* auto write realloc enabled */
+       u_char  arre            : 1;    /* auto read realloc enabled */
+       u_char  tb              : 1;    /* transfer block */
+       u_char  rc              : 1;    /* read continuous */
+       u_char  eec             : 1;    /* enable early correction */
+       u_char  per             : 1;    /* post error */
+       u_char  dte             : 1;    /* disable transfer on error */
+       u_char  dcr             : 1;    /* disable correction */
+       u_char  retry_count;
+       u_char  correction_span;
+       u_char  head_offset_count;
+       u_char  strobe_offset_count;
+       u_char  recovery_time_limit;
+};
+
+/*
+ * Page Two - Disconnect / Reconnect Control Parameters
+ */
+struct scsi_disco_reco {
+       u_char  page_savable    : 1;    /* save parameters */
+       u_char  rsvd            : 1;
+       u_char  page_code       : 6;    /* = 0x02 */
+       u_char  page_length;            /* = 10 */
+       u_char  buffer_full_ratio;      /* write, how full before reconnect? */
+       u_char  buffer_empty_ratio;     /* read, how full before reconnect? */
+
+       u_short bus_inactivity_limit;   /* how much bus time for busy */
+       u_short disconnect_time_limit;  /* min to remain disconnected */
+       u_short connect_time_limit;     /* min to remain connected */
+       u_short reserved_1;
+};
+
+/*
+ * Page Three - Direct Access Device Format Parameters
+ */
+struct scsi_format {
+       u_char  page_savable    : 1;    /* save parameters */
+       u_char  rsvd            : 1;
+       u_char  page_code       : 6;    /* = 0x03 */
+       u_char  page_length;            /* = 22 */
+       u_short tracks_per_zone;        /*  Handling of Defects Fields */
+       u_short alt_sect_zone;
+       u_short alt_tracks_zone;
+       u_short alt_tracks_vol;
+       u_short sect_track;             /* Track Format Field */
+       u_short data_sect;              /* Sector Format Fields */
+       u_short interleave;
+       u_short track_skew_factor;
+       u_short cyl_skew_factor;
+       u_char  ssec            : 1;    /* Drive Type Field */
+       u_char  hsec            : 1;
+       u_char  rmb             : 1;
+       u_char  surf            : 1;
+       u_char  ins             : 1;
+       u_char  reserved_1      : 3;
+       u_char  reserved_2;
+       u_char  reserved_3;
+       u_char  reserved_4;
+};
+
+/*
+ * Page Four - Rigid Disk Drive Geometry Parameters 
+ */
+struct scsi_geometry {
+       u_char  page_savable    : 1;    /* save parameters */
+       u_char  rsvd            : 1;
+       u_char  page_code       : 6;    /* = 0x04 */
+       u_char  page_length;            /* = 18 */
+       u_char  cyl_ub;                 /* number of cylinders */
+       u_char  cyl_mb;
+       u_char  cyl_lb;
+       u_char  heads;                  /* number of heads */
+       u_char  precomp_cyl_ub;         /* cylinder to start precomp */
+       u_char  precomp_cyl_mb;
+       u_char  precomp_cyl_lb;
+       u_char  current_cyl_ub;         /* cyl to start reduced current */
+       u_char  current_cyl_mb;
+       u_char  current_cyl_lb;
+       u_short step_rate;              /* drive step rate */
+       u_char  landing_cyl_ub;         /* landing zone cylinder */
+       u_char  landing_cyl_mb;
+       u_char  landing_cyl_lb;
+       u_char  reserved_1;
+       u_char  reserved_2;
+       u_char  reserved_3;
+};
+
+/*
+ * Page 0x38 - Cache Control Parameters
+ */
+struct scsi_cache {
+       u_char  page_savable    : 1;    /* save parameters */
+       u_char  rsvd            : 1;
+       u_char  page_code       : 6;    /* = 0x38 */
+       u_char  page_length;            /* = 14 */
+       u_char rsvd_1   : 1;
+       u_char wie      : 1;            /* write index enable */
+       u_char rsvd_2   : 1;
+       u_char ce       : 1;            /* cache enable */
+       u_char table_size : 4;
+       u_char  prefetch_threshold;
+       u_char  maximum_threshold;
+       u_char  maximumprefetch_multiplier;
+       u_char  minimum_threshold;
+       u_char  minimum_prefetch_multiplier;
+       u_char  reserved[8];
+};
+
+/*
+ * Driver ioctl's for various scsi operations.
+ */
+#ifndef _IOCTL_
+#include "ioctl.h"
+#endif
+
+/*
+ * Control for SCSI "format" mode.
+ *
+ * "Format" mode allows a privileged process to issue direct SCSI
+ * commands to a drive (it is intended primarily to allow on-line
+ * formatting).  SDIOCSFORMAT with a non-zero arg will put the drive
+ * into format mode; a zero arg will take it out.  When in format
+ * mode, only the process that issued the SDIOCFORMAT can read or
+ * write the drive.
+ *
+ * In format mode, process is expected to
+ *     - do SDIOCSCSICOMMAND to supply cdb for next SCSI op
+ *     - do read or write as appropriate for cdb
+ *     - if i/o error, optionally do SDIOCSENSE to get completion
+ *       status and sense data from last scsi operation.
+ */
+
+struct scsi_fmt_cdb {
+       int len;                /* cdb length (in bytes) */
+       u_char cdb[28];         /* cdb to use on next read/write */
+};
+
+struct scsi_fmt_sense {
+       u_int status;           /* completion status of last op */
+       u_char sense[28];       /* sense data (if any) from last op */
+};
+
+#define        SDIOCSFORMAT            _IOW('S', 0x1, int)
+#define        SDIOCGFORMAT            _IOR('S', 0x2, int)
+#define        SDIOCSCSICOMMAND        _IOW('S', 0x3, struct scsi_fmt_cdb)
+#define        SDIOCSENSE              _IOR('S', 0x4, struct scsi_fmt_sense)
diff --git a/usr/src/sys/hp300/dev/scsivar.h b/usr/src/sys/hp300/dev/scsivar.h
new file mode 100644 (file)
index 0000000..65a0bb9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)scsivar.h   7.1 (Berkeley) %G%
+ */
+
+struct scsi_softc {
+       struct  hp_ctlr *sc_hc;
+       struct  devqueue sc_dq;
+       struct  devqueue sc_sq;
+       u_char  sc_flags;
+       u_char  sc_sync;
+       u_char  sc_scsi_addr;
+       u_char  sc_stat[2];
+       u_char  sc_msg[7];
+};
+
+/* sc_flags */
+#define        SCSI_IO         0x80    /* DMA I/O in progress */
+#define        SCSI_DMA32      0x40    /* 32-bit DMA should be used */
+#define        SCSI_ALIVE      0x01    /* controller initialized */
+#ifdef DEBUG
+#define        SCSI_PAD        0x02    /* 'padded' transfer in progress */
+#endif
diff --git a/usr/src/sys/hp300/dev/sd.c b/usr/src/sys/hp300/dev/sd.c
new file mode 100644 (file)
index 0000000..0a25bf9
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sd.c        7.1 (Berkeley) %G%
+ */
+
+/*
+ * SCSI CCS (Command Command Set) disk driver.
+ */
+#include "sd.h"
+#if NSD > 0
+
+#ifndef lint
+static char rcsid[] = "$Header: sd.c,v 1.5 90/01/10 16:06:12 mike Locked $";
+#endif
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "errno.h"
+#include "dkstat.h"
+#include "disklabel.h"
+#include "device.h"
+#include "malloc.h"
+#include "scsireg.h"
+
+#include "user.h"
+#include "proc.h"
+#include "uio.h"
+
+extern int scsi_test_unit_rdy();
+extern int scsi_request_sense();
+extern int scsi_inquiry();
+extern int scsi_read_capacity();
+extern int scsi_tt_write();
+extern int scsireq();
+extern int scsiustart();
+extern int scsigo();
+extern void scsifree();
+extern void scsireset();
+
+extern void printf();
+extern void bcopy();
+extern void disksort();
+extern int splbio();
+extern void splx();
+extern void biodone();
+extern int physio();
+extern void TBIS();
+
+int    sdinit();
+void   sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
+
+struct driver sddriver = {
+       sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
+};
+
+struct size {
+       u_long  strtblk;
+       u_long  endblk;
+       int     nblocks;
+};
+
+struct sdinfo {
+       struct  size part[8];
+};
+
+/*
+ * since the SCSI standard tends to hide the disk structure, we define
+ * partitions in terms of DEV_BSIZE blocks.  The default partition table
+ * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
+ * root and 32 meg of swap.  The rest of the space on the drive goes in
+ * the G partition.  As usual, the C partition covers the entire disk
+ * (including the boot area).
+ */
+struct sdinfo sddefaultpart = {
+            1024,   17408,   16384   , /* A */
+           17408,   82944,   65536   , /* B */
+               0,       0,       0   , /* C */
+           17408,  115712,   98304   , /* D */
+          115712,  218112,  102400   , /* E */
+          218112,       0,       0   , /* F */
+           82944,       0,       0   , /* G */
+          115712,       0,       0   , /* H */
+};
+
+struct sd_softc {
+       struct  hp_device *sc_hd;
+       struct  devqueue sc_dq;
+       int     sc_format_pid;  /* process using "format" mode */
+       short   sc_flags;
+       short   sc_type;        /* drive type */
+       short   sc_punit;       /* physical unit (scsi lun) */
+       u_short sc_bshift;      /* convert device blocks to DEV_BSIZE blks */
+       u_int   sc_blks;        /* number of blocks on device */
+       int     sc_blksize;     /* device block size in bytes */
+       u_int   sc_wpms;        /* average xfer rate in 16 bit wds/sec. */
+       struct  sdinfo sc_info; /* drive partition table & label info */
+} sd_softc[NSD];
+
+/* sc_flags values */
+#define        SDF_ALIVE       0x1
+
+#ifdef DEBUG
+int sddebug = 1;
+#define SDB_ERROR      0x01
+#define SDB_PARTIAL    0x02
+#endif
+
+struct sdstats {
+       long    sdresets;
+       long    sdtransfers;
+       long    sdpartials;
+} sdstats[NSD];
+
+struct buf sdtab[NSD];
+struct buf sdbuf[NSD];
+struct scsi_fmt_cdb sdcmd[NSD];
+struct scsi_fmt_sense sdsense[NSD];
+
+static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
+static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
+
+#define        sdunit(x)       ((minor(x) >> 3) & 0x7)
+#define sdpart(x)      (minor(x) & 0x7)
+#define        sdpunit(x)      ((x) & 7)
+#define        b_cylin         b_resid
+#define        SDRETRY         2
+
+/*
+ * Table of scsi commands users are allowed to access via "format"
+ * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
+ * -1 means needs dma and/or wait for intr.
+ */
+static char legal_cmds[256] = {
+/*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
+/*00*/ 0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*10*/ 0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
+/*20*/ 0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*30*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*40*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*50*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*60*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*70*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*80*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*90*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*a0*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*b0*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*c0*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*d0*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*e0*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+/*f0*/ 0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static struct scsi_inquiry inqbuf;
+static struct scsi_fmt_cdb inq = {
+       6,
+       CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
+};
+
+static u_char capbuf[8];
+struct scsi_fmt_cdb cap = {
+       10,
+       CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int
+sdident(sc, hd)
+       struct sd_softc *sc;
+       struct hp_device *hd;
+{
+       int unit;
+       register int ctlr, slave;
+       register int i;
+       register int tries = 10;
+
+       ctlr = hd->hp_ctlr;
+       slave = hd->hp_slave;
+       unit = sc->sc_punit;
+
+       /*
+        * See if unit exists and is a disk then read block size & nblocks.
+        */
+       while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
+               if (i == -1 || --tries < 0)
+                       /* doesn't exist or not a CCS device */
+                       return (-1);
+               if (i == STS_CHECKCOND) {
+                       u_char sensebuf[128];
+                       struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
+
+                       scsi_request_sense(ctlr, slave, unit, sensebuf,
+                                          sizeof(sensebuf));
+                       if (sp->class == 7 && sp->key == 6)
+                               /* drive doing an RTZ -- give it a while */
+                               DELAY(1000000);
+               }
+               DELAY(1000);
+       }
+       if (scsi_immed_command(ctlr, slave, unit, &inq, (u_char *)&inqbuf,
+                              sizeof(inqbuf), B_READ) ||
+           scsi_immed_command(ctlr, slave, unit, &cap, (u_char *)&capbuf,
+                              sizeof(capbuf), B_READ))
+               /* doesn't exist or not a CCS device */
+               return (-1);
+
+       switch (inqbuf.type) {
+       case 0:         /* disk */
+       case 4:         /* WORM */
+       case 5:         /* CD-ROM */
+       case 7:         /* Magneto-optical */
+               break;
+       default:        /* not a disk */
+               return (-1);
+       }
+       sc->sc_blks = *(u_int *)&capbuf[0];
+       sc->sc_blksize = *(int *)&capbuf[4];
+
+       if (inqbuf.version != 1)
+               printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
+                       inqbuf.type, inqbuf.qual, inqbuf.version);
+       else {
+               char idstr[32];
+
+               bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
+               for (i = 27; i > 23; --i)
+                       if (idstr[i] != ' ')
+                               break;
+               idstr[i+1] = 0;
+               for (i = 23; i > 7; --i)
+                       if (idstr[i] != ' ')
+                               break;
+               idstr[i+1] = 0;
+               for (i = 7; i >= 0; --i)
+                       if (idstr[i] != ' ')
+                               break;
+               idstr[i+1] = 0;
+               printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
+                       &idstr[24]);
+       }
+       printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
+       if (sc->sc_blksize != DEV_BSIZE) {
+               if (sc->sc_blksize < DEV_BSIZE) {
+                       printf("sd%d: need %d byte blocks - drive ignored\n",
+                               unit, DEV_BSIZE);
+                       return (-1);
+               }
+               for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
+                       ++sc->sc_bshift;
+               sc->sc_blks <<= sc->sc_bshift;
+       }
+       sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);        /* XXX */
+       return(inqbuf.type);
+}
+
+int
+sdinit(hd)
+       register struct hp_device *hd;
+{
+       register struct sd_softc *sc = &sd_softc[hd->hp_unit];
+
+       sc->sc_hd = hd;
+       sc->sc_punit = sdpunit(hd->hp_flags);
+       sc->sc_type = sdident(sc, hd);
+       if (sc->sc_type < 0)
+               return(0);
+       sc->sc_dq.dq_ctlr = hd->hp_ctlr;
+       sc->sc_dq.dq_unit = hd->hp_unit;
+       sc->sc_dq.dq_slave = hd->hp_slave;
+       sc->sc_dq.dq_driver = &sddriver;
+
+       /*
+        * If we don't have a disk label, build a default partition
+        * table with 'standard' size root & swap and everything else
+        * in the G partition.
+        */
+       sc->sc_info = sddefaultpart;
+       /* C gets everything */
+       sc->sc_info.part[2].nblocks = sc->sc_blks;
+       sc->sc_info.part[2].endblk = sc->sc_blks;
+       /* G gets from end of B to end of disk */
+       sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk;
+       sc->sc_info.part[6].endblk = sc->sc_blks;
+       /*
+        * We also define the D, E and F paritions as an alternative to
+        * B and G.  D is 48Mb, starts after A and is intended for swapping.
+        * E is 50Mb, starts after D and is intended for /usr. F starts
+        * after E and is what ever is left.
+        */
+       if (sc->sc_blks >= sc->sc_info.part[4].endblk) {
+               sc->sc_info.part[5].nblocks =
+                       sc->sc_blks - sc->sc_info.part[4].endblk;
+               sc->sc_info.part[5].endblk = sc->sc_blks;
+       } else {
+               sc->sc_info.part[5].strtblk = 0;
+               sc->sc_info.part[3] = sc->sc_info.part[5];
+               sc->sc_info.part[4] = sc->sc_info.part[5];
+       }
+       /*
+        * H is a single partition alternative to E and F.
+        */
+       if (sc->sc_blks >= sc->sc_info.part[3].endblk) {
+               sc->sc_info.part[7].nblocks =
+                       sc->sc_blks - sc->sc_info.part[3].endblk;
+               sc->sc_info.part[7].endblk = sc->sc_blks;
+       } else {
+               sc->sc_info.part[7].strtblk = 0;
+       }
+
+       sc->sc_flags = SDF_ALIVE;
+       return(1);
+}
+
+void
+sdreset(sc, hd)
+       register struct sd_softc *sc;
+       register struct hp_device *hd;
+{
+       sdstats[hd->hp_unit].sdresets++;
+}
+
+int
+sdopen(dev, flags)
+       dev_t dev;
+       int flags;
+{
+       register int unit = sdunit(dev);
+       register struct sd_softc *sc = &sd_softc[unit];
+
+       if (unit >= NSD)
+               return(ENXIO);
+       if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(u.u_cred, &u.u_acflag))
+               return(ENXIO);
+
+       if (sc->sc_hd->hp_dk >= 0)
+               dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
+       return(0);
+}
+
+/*
+ * This routine is called for partial block transfers and non-aligned
+ * transfers (the latter only being possible on devices with a block size
+ * larger than DEV_BSIZE).  The operation is performed in three steps
+ * using a locally allocated buffer:
+ *     1. transfer any initial partial block
+ *     2. transfer full blocks
+ *     3. transfer any final partial block
+ */
+static void
+sdlblkstrat(bp, bsize)
+       register struct buf *bp;
+       register int bsize;
+{
+       register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
+                                                       M_DEVBUF, M_WAITOK);
+       caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
+       register int bn, resid;
+       register caddr_t addr;
+
+       bzero((caddr_t)cbp, sizeof(*cbp));
+       cbp->b_proc = u.u_procp;
+       cbp->b_dev = bp->b_dev;
+       bn = bp->b_blkno;
+       resid = bp->b_bcount;
+       addr = bp->b_un.b_addr;
+#ifdef DEBUG
+       if (sddebug & SDB_PARTIAL)
+               printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
+                      bp, bp->b_flags, bn, resid, addr);
+#endif
+
+       while (resid > 0) {
+               register int boff = dbtob(bn) & (bsize - 1);
+               register int count;
+
+               if (boff || resid < bsize) {
+                       sdstats[sdunit(bp->b_dev)].sdpartials++;
+                       count = MIN(resid, bsize - boff);
+                       cbp->b_flags = B_BUSY | B_PHYS | B_READ;
+                       cbp->b_blkno = bn - btodb(boff);
+                       cbp->b_un.b_addr = cbuf;
+                       cbp->b_bcount = bsize;
+#ifdef DEBUG
+                       if (sddebug & SDB_PARTIAL)
+                               printf(" readahead: bn %x cnt %x off %x addr %x\n",
+                                      cbp->b_blkno, count, boff, addr);
+#endif
+                       sdstrategy(cbp);
+                       biowait(cbp);
+                       if (cbp->b_flags & B_ERROR) {
+                               bp->b_flags |= B_ERROR;
+                               bp->b_error = cbp->b_error;
+                               break;
+                       }
+                       if (bp->b_flags & B_READ) {
+                               bcopy(&cbuf[boff], addr, count);
+                               goto done;
+                       }
+                       bcopy(addr, &cbuf[boff], count);
+#ifdef DEBUG
+                       if (sddebug & SDB_PARTIAL)
+                               printf(" writeback: bn %x cnt %x off %x addr %x\n",
+                                      cbp->b_blkno, count, boff, addr);
+#endif
+               } else {
+                       count = resid & ~(bsize - 1);
+                       cbp->b_blkno = bn;
+                       cbp->b_un.b_addr = addr;
+                       cbp->b_bcount = count;
+#ifdef DEBUG
+                       if (sddebug & SDB_PARTIAL)
+                               printf(" fulltrans: bn %x cnt %x addr %x\n",
+                                      cbp->b_blkno, count, addr);
+#endif
+               }
+               cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
+               sdstrategy(cbp);
+               biowait(cbp);
+               if (cbp->b_flags & B_ERROR) {
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = cbp->b_error;
+                       break;
+               }
+done:
+               bn += btodb(count);
+               resid -= count;
+               addr += count;
+#ifdef DEBUG
+               if (sddebug & SDB_PARTIAL)
+                       printf(" done: bn %x resid %x addr %x\n",
+                              bn, resid, addr);
+#endif
+       }
+       free(cbuf, M_DEVBUF);
+       free(cbp, M_DEVBUF);
+}
+
+void
+sdstrategy(bp)
+       register struct buf *bp;
+{
+       register int part = sdpart(bp->b_dev);
+       register int unit = sdunit(bp->b_dev);
+       register int bn, sz;
+       register struct sd_softc *sc = &sd_softc[unit];
+       register struct buf *dp = &sdtab[unit];
+       register int s;
+
+       if (sc->sc_format_pid) {
+               if (sc->sc_format_pid != u.u_procp->p_pid) {
+                       bp->b_error = EPERM;
+                       goto bad;
+               }
+               bp->b_cylin = 0;
+       } else {
+               bn = bp->b_blkno;
+               sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT;
+               if (bn < 0 || bn + sz > sc->sc_info.part[part].nblocks) {
+                       if (bn == sc->sc_info.part[part].nblocks) {
+                               bp->b_resid = bp->b_bcount;
+                               goto done;
+                       }
+                       bp->b_error = EINVAL;
+                       goto bad;
+               }
+               /*
+                * Non-aligned or partial-block transfers handled specially.
+                */
+               s = sc->sc_blksize - 1;
+               if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
+                       sdlblkstrat(bp, sc->sc_blksize);
+                       goto done;
+               }
+               bp->b_cylin = (bn + sc->sc_info.part[part].strtblk) >>
+                               sc->sc_bshift;
+       }
+       s = splbio();
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               dp->b_active = 1;
+               sdustart(unit);
+       }
+       splx(s);
+       return;
+bad:
+       bp->b_flags |= B_ERROR;
+done:
+       iodone(bp);
+}
+
+void
+sdustart(unit)
+       register int unit;
+{
+       if (scsireq(&sd_softc[unit].sc_dq))
+               sdstart(unit);
+}
+
+static void
+sderror(unit, sc, hp, stat)
+       int unit, stat;
+       register struct sd_softc *sc;
+       register struct hp_device *hp;
+{
+       sdsense[unit].status = stat;
+       if (stat & STS_CHECKCOND) {
+               struct scsi_xsense *sp;
+
+               scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
+                                  sc->sc_punit, sdsense[unit].sense,
+                                  sizeof(sdsense[unit].sense));
+               sp = (struct scsi_xsense *)sdsense[unit].sense;
+               printf("sd%d: scsi sense class %d, code %d", unit,
+                       sp->class, sp->code);
+               if (sp->class == 7) {
+                       printf(", key %d", sp->key);
+                       if (sp->valid)
+                               printf(", blk %d", *(int *)&sp->info1);
+               }
+               printf("\n");
+       }
+}
+
+static void
+sdfinish(unit, sc, bp)
+       int unit;
+       register struct sd_softc *sc;
+       register struct buf *bp;
+{
+       sdtab[unit].b_errcnt = 0;
+       sdtab[unit].b_actf = bp->b_actf;
+       bp->b_resid = 0;
+       iodone(bp);
+       scsifree(&sc->sc_dq);
+       if (sdtab[unit].b_actf)
+               sdustart(unit);
+       else
+               sdtab[unit].b_active = 0;
+}
+
+void
+sdstart(unit)
+       register int unit;
+{
+       register struct sd_softc *sc = &sd_softc[unit];
+       register struct hp_device *hp = sc->sc_hd;
+
+       /*
+        * we have the SCSI bus -- in format mode, we may or may not need dma
+        * so check now.
+        */
+       if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
+               register struct buf *bp = sdtab[unit].b_actf;
+               register int sts;
+
+               sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
+                                        sc->sc_punit, &sdcmd[unit],
+                                        bp->b_un.b_addr, bp->b_bcount,
+                                        bp->b_flags & B_READ);
+               sdsense[unit].status = sts;
+               if (sts & 0xfe) {
+                       sderror(unit, sc, hp, sts);
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = EIO;
+               }
+               sdfinish(unit, sc, bp);
+
+       } else if (scsiustart(hp->hp_ctlr))
+               sdgo(unit);
+}
+
+void
+sdgo(unit)
+       register int unit;
+{
+       register struct sd_softc *sc = &sd_softc[unit];
+       register struct hp_device *hp = sc->sc_hd;
+       register struct buf *bp = sdtab[unit].b_actf;
+       register int pad;
+       register struct scsi_fmt_cdb *cmd;
+
+       if (sc->sc_format_pid) {
+               cmd = &sdcmd[unit];
+               pad = 0;
+       } else {
+               cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
+               *(int *)(&cmd->cdb[2]) = bp->b_cylin;
+               pad = howmany(bp->b_bcount, sc->sc_blksize);
+               *(u_short *)(&cmd->cdb[7]) = pad;
+               pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
+#ifdef DEBUG
+               if (pad)
+                       printf("sd%d: partial block xfer -- %x bytes\n",
+                              unit, bp->b_bcount);
+#endif
+               sdstats[unit].sdtransfers++;
+       }
+       if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
+               if (hp->hp_dk >= 0) {
+                       dk_busy |= 1 << hp->hp_dk;
+                       ++dk_seek[hp->hp_dk];
+                       ++dk_xfer[hp->hp_dk];
+                       dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
+               }
+               return;
+       }
+#ifdef DEBUG
+       if (sddebug & SDB_ERROR)
+               printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
+                      unit, bp->b_flags & B_READ? "read" : "write",
+                      bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
+                      sdtab[unit].b_errcnt);
+#endif
+       bp->b_flags |= B_ERROR;
+       bp->b_error = EIO;
+       sdfinish(unit, sc, bp);
+}
+
+void
+sdintr(unit, stat)
+       register int unit;
+       int stat;
+{
+       register struct sd_softc *sc = &sd_softc[unit];
+       register struct buf *bp = sdtab[unit].b_actf;
+       register struct hp_device *hp = sc->sc_hd;
+       
+       if (bp == NULL) {
+               printf("sd%d: bp == NULL\n", unit);
+               return;
+       }
+       if (hp->hp_dk >= 0)
+               dk_busy &=~ (1 << hp->hp_dk);
+       if (stat) {
+#ifdef DEBUG
+               if (sddebug & SDB_ERROR)
+                       printf("sd%d: sdintr: bad scsi status 0x%x\n",
+                               unit, stat);
+#endif
+               sderror(unit, sc, hp, stat);
+               bp->b_flags |= B_ERROR;
+               bp->b_error = EIO;
+       }
+       sdfinish(unit, sc, bp);
+}
+
+int
+sdread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = sdunit(dev);
+       register int pid;
+
+       if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid)
+               return (EPERM);
+               
+       return(physio(sdstrategy, &sdbuf[unit], dev, B_READ, minphys, uio));
+}
+
+int
+sdwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = sdunit(dev);
+       register int pid;
+
+       if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid)
+               return (EPERM);
+               
+       return(physio(sdstrategy, &sdbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+int
+sdioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       caddr_t data;
+       int flag;
+{
+       register int unit = sdunit(dev);
+       register struct sd_softc *sc = &sd_softc[unit];
+
+       switch (cmd) {
+       default:
+               return (EINVAL);
+
+       case SDIOCSFORMAT:
+               /* take this device into or out of "format" mode */
+               if (suser(u.u_cred, &u.u_acflag))
+                       return(EPERM);
+
+               if (*(int *)data) {
+                       if (sc->sc_format_pid)
+                               return (EPERM);
+                       sc->sc_format_pid = u.u_procp->p_pid;
+               } else
+                       sc->sc_format_pid = 0;
+               return (0);
+
+       case SDIOCGFORMAT:
+               /* find out who has the device in format mode */
+               *(int *)data = sc->sc_format_pid;
+               return (0);
+
+       case SDIOCSCSICOMMAND:
+               /*
+                * Save what user gave us as SCSI cdb to use with next
+                * read or write to the char device.
+                */
+               if (sc->sc_format_pid != u.u_procp->p_pid)
+                       return (EPERM);
+               if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
+                       return (EINVAL);
+               bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
+               return (0);
+
+       case SDIOCSENSE:
+               /*
+                * return the SCSI sense data saved after the last
+                * operation that completed with "check condition" status.
+                */
+               bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
+               return (0);
+               
+       }
+       /*NOTREACHED*/
+}
+
+int
+sdsize(dev)
+       dev_t dev;
+{
+       register int unit = sdunit(dev);
+       register struct sd_softc *sc = &sd_softc[unit];
+
+       if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
+               return(-1);
+
+       return(sc->sc_info.part[sdpart(dev)].nblocks);
+}
+
+#include "machine/pte.h"
+#include "machine/vmparam.h"
+#include "../h/vmmac.h"
+
+/*
+ * Non-interrupt driven, non-dma dump routine.
+ */
+int
+sddump(dev)
+       dev_t dev;
+{
+       int part = sdpart(dev);
+       int unit = sdunit(dev);
+       register struct sd_softc *sc = &sd_softc[unit];
+       register struct hp_device *hp = sc->sc_hd;
+       register daddr_t baddr;
+       register int maddr;
+       register int pages, i;
+       int stat;
+       extern int lowram;
+
+       /*
+        * Hmm... all vax drivers dump maxfree pages which is physmem minus
+        * the message buffer.  Is there a reason for not dumping the
+        * message buffer?  Savecore expects to read 'dumpsize' pages of
+        * dump, where dumpsys() sets dumpsize to physmem!
+        */
+       pages = physmem;
+
+       /* is drive ok? */
+       if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
+               return (ENXIO);
+       /* dump parameters in range? */
+       if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks)
+               return (EINVAL);
+       if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks)
+               pages = dtoc(sc->sc_info.part[part].nblocks - dumplo);
+       maddr = lowram;
+       baddr = dumplo + sc->sc_info.part[part].strtblk;
+       /* scsi bus idle? */
+       if (!scsireq(&sc->sc_dq)) {
+               scsireset(hp->hp_ctlr);
+               sdreset(sc, sc->sc_hd);
+               printf("[ drive %d reset ] ", unit);
+       }
+       for (i = 0; i < pages; i++) {
+#define NPGMB  (1024*1024/NBPG)
+               /* print out how many Mbs we have dumped */
+               if (i && (i % NPGMB) == 0)
+                       printf("%d ", i / NPGMB);
+#undef NPBMG
+               mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V);
+               stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
+                                    vmmap, NBPG, baddr, sc->sc_bshift);
+               if (stat) {
+                       printf("sddump: scsi write error 0x%x\n", stat);
+                       return (EIO);
+               }
+               maddr += NBPG;
+               baddr += ctod(1);
+       }
+       return (0);
+}
+#endif