summaryrefslogtreecommitdiff
path: root/sys/dev/ieee488
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ieee488')
-rw-r--r--sys/dev/ieee488/ibfoo.c1005
-rw-r--r--sys/dev/ieee488/ibfoo_int.h147
-rw-r--r--sys/dev/ieee488/pcii.c192
-rw-r--r--sys/dev/ieee488/ugpib.h155
-rw-r--r--sys/dev/ieee488/upd7210.c291
-rw-r--r--sys/dev/ieee488/upd7210.h234
6 files changed, 2024 insertions, 0 deletions
diff --git a/sys/dev/ieee488/ibfoo.c b/sys/dev/ieee488/ibfoo.c
new file mode 100644
index 000000000000..537443dbf091
--- /dev/null
+++ b/sys/dev/ieee488/ibfoo.c
@@ -0,0 +1,1005 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * High-level driver for µPD7210 based GPIB cards.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+# define IBDEBUG
+# undef IBDEBUG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <isa/isavar.h>
+
+#include <dev/ieee488/ugpib.h>
+
+#define UPD7210_SW_DRIVER
+#include <dev/ieee488/upd7210.h>
+
+static MALLOC_DEFINE(M_IBFOO, "IBFOO", "IBFOO");
+
+
+/* ibfoo API */
+
+#include <dev/ieee488/ibfoo_int.h>
+
+/* XXX: This is really a bitmap */
+enum h_kind {
+ H_DEV = 1,
+ H_BOARD = 2,
+ H_EITHER = 3
+};
+
+struct handle {
+ LIST_ENTRY(handle) list;
+ int handle;
+ enum h_kind kind;
+ int pad;
+ int sad;
+ struct timeval timeout;
+ int eot;
+ int eos;
+ int dma;
+};
+
+struct ibfoo {
+ struct upd7210 *u;
+ LIST_HEAD(,handle) handles;
+ struct unrhdr *unrhdr;
+ struct callout callout;
+ struct handle *h;
+ struct ibarg *ap;
+
+ enum {
+ IDLE,
+ BUSY,
+ PIO_IDATA,
+ PIO_ODATA,
+ PIO_CMD,
+ DMA_IDATA
+ } mode;
+
+ struct timeval deadline;
+
+ struct handle *rdh; /* addressed for read */
+ struct handle *wrh; /* addressed for write */
+
+ int doeoi;
+
+ u_char *buf;
+ u_int buflen;
+};
+
+typedef int ibhandler_t(struct ibfoo *ib);
+
+static struct timeval timeouts[] = {
+ [TNONE] = { 0, 0},
+ [T10us] = { 0, 10},
+ [T30us] = { 0, 30},
+ [T100us] = { 0, 100},
+ [T300us] = { 0, 300},
+ [T1ms] = { 0, 1000},
+ [T3ms] = { 0, 3000},
+ [T10ms] = { 0, 10000},
+ [T30ms] = { 0, 30000},
+ [T100ms] = { 0, 100000},
+ [T300ms] = { 0, 300000},
+ [T1s] = { 1, 0},
+ [T3s] = { 3, 0},
+ [T10s] = { 10, 0},
+ [T30s] = { 30, 0},
+ [T100s] = { 100, 0},
+ [T300s] = { 300, 0},
+ [T1000s] = { 1000, 0}
+};
+
+static const u_int max_timeouts = sizeof timeouts / sizeof timeouts[0];
+
+static int ibdebug;
+
+static int
+ib_set_error(struct ibarg *ap, int error)
+{
+
+ if (ap->__iberr == 0)
+ ap->__iberr = error;
+ ap->__ibsta |= ERR;
+ ap->__retval = ap->__ibsta;
+ return (0);
+}
+
+static int
+ib_had_timeout(struct ibarg *ap)
+{
+
+ ib_set_error(ap, EABO);
+ ap->__ibsta |= TIMO;
+ ap->__retval = ap->__ibsta;
+ return (0);
+}
+
+static int
+ib_set_errno(struct ibarg *ap, int errno)
+{
+
+ if (ap->__iberr == 0) {
+ ap->__iberr = EDVR;
+ ap->__ibcnt = errno;
+ }
+ ap->__ibsta |= ERR;
+ ap->__retval = ap->__ibsta;
+ return (0);
+}
+
+static int
+gpib_ib_irq(struct upd7210 *u, int intr __unused)
+{
+ struct ibfoo *ib;
+
+ ib = u->ibfoo;
+
+ mtx_assert(&u->mutex, MA_OWNED);
+ switch (ib->mode) {
+ case PIO_CMD:
+ if (!(u->rreg[ISR2] & IXR2_CO))
+ return (0);
+ if (ib->buflen == 0)
+ break;
+ upd7210_wr(u, CDOR, *ib->buf);
+ ib->buf++;
+ ib->buflen--;
+ return (1);
+ case PIO_IDATA:
+ if (!(u->rreg[ISR1] & IXR1_DI))
+ return (0);
+ *ib->buf = upd7210_rd(u, DIR);
+ ib->buf++;
+ ib->buflen--;
+ if (ib->buflen == 0 || (u->rreg[ISR1] & IXR1_ENDRX))
+ break;
+ return (1);
+ case PIO_ODATA:
+ if (!(u->rreg[ISR1] & IXR1_DO))
+ return (0);
+ if (ib->buflen == 0)
+ break;
+ if (ib->buflen == 1 && ib->doeoi)
+ upd7210_wr(u, AUXMR, AUXMR_SEOI);
+ upd7210_wr(u, CDOR, *ib->buf);
+ ib->buf++;
+ ib->buflen--;
+ return (1);
+ case DMA_IDATA:
+ if (!(u->rreg[ISR1] & IXR1_ENDRX))
+ return (0);
+ break;
+ default:
+ return (0);
+ }
+ upd7210_wr(u, IMR1, 0);
+ upd7210_wr(u, IMR2, 0);
+ ib->mode = BUSY;
+ wakeup(&ib->buflen);
+ return (1);
+}
+
+static void
+gpib_ib_timeout(void *arg)
+{
+ struct upd7210 *u;
+ struct ibfoo *ib;
+ struct timeval tv;
+
+ u = arg;
+ ib = u->ibfoo;
+ mtx_lock(&u->mutex);
+ if (ib->mode == DMA_IDATA && isa_dmatc(u->dmachan)) {
+ KASSERT(u->dmachan >= 0, ("Bogus dmachan = %d", u->dmachan));
+ upd7210_wr(u, IMR1, 0);
+ upd7210_wr(u, IMR2, 0);
+ ib->mode = BUSY;
+ wakeup(&ib->buflen);
+ }
+ if (ib->mode > BUSY) {
+ upd7210_rd(u, ISR1);
+ upd7210_rd(u, ISR2);
+ gpib_ib_irq(u, 2);
+ }
+ if (ib->mode != IDLE && timevalisset(&ib->deadline)) {
+ getmicrouptime(&tv);
+ if (timevalcmp(&ib->deadline, &tv, <)) {
+ ib_had_timeout(ib->ap);
+ upd7210_wr(u, IMR1, 0);
+ upd7210_wr(u, IMR2, 0);
+ ib->mode = BUSY;
+ wakeup(&ib->buflen);
+ }
+ }
+ if (ib->mode != IDLE)
+ callout_reset(&ib->callout, hz / 5, gpib_ib_timeout, arg);
+ mtx_unlock(&u->mutex);
+}
+
+static void
+gpib_ib_wait_xfer(struct upd7210 *u, struct ibfoo *ib)
+{
+ int i;
+
+ mtx_assert(&u->mutex, MA_OWNED);
+ while (ib->mode > BUSY) {
+ i = msleep(&ib->buflen, &u->mutex,
+ PZERO | PCATCH, "ibwxfr", 0);
+ if (i == EINTR) {
+ ib_set_errno(ib->ap, i);
+ break;
+ }
+ if (u->rreg[ISR1] & IXR1_ERR) {
+ ib_set_error(ib->ap, EABO); /* XXX ? */
+ break;
+ }
+ }
+ ib->mode = BUSY;
+ ib->buf = NULL;
+ upd7210_wr(u, IMR1, 0);
+ upd7210_wr(u, IMR2, 0);
+}
+
+static void
+config_eos(struct upd7210 *u, struct handle *h)
+{
+ int i;
+
+ i = 0;
+ if (h->eos & REOS) {
+ upd7210_wr(u, EOSR, h->eos & 0xff);
+ i |= AUXA_REOS;
+ }
+ if (h->eos & XEOS) {
+ upd7210_wr(u, EOSR, h->eos & 0xff);
+ i |= AUXA_XEOS;
+ }
+ if (h->eos & BIN)
+ i |= AUXA_BIN;
+ upd7210_wr(u, AUXRA, C_AUXA | i);
+}
+
+/*
+ * Look up the handle, and set the deadline if the handle has a timeout.
+ */
+static int
+gethandle(struct upd7210 *u, struct ibarg *ap, struct handle **hp)
+{
+ struct ibfoo *ib;
+ struct handle *h;
+
+ KASSERT(ap->__field & __F_HANDLE, ("gethandle without __F_HANDLE"));
+ ib = u->ibfoo;
+ LIST_FOREACH(h, &ib->handles, list) {
+ if (h->handle == ap->handle) {
+ *hp = h;
+ return (0);
+ }
+ }
+ ib_set_error(ap, EARG);
+ return (1);
+}
+
+static int
+pio_cmd(struct upd7210 *u, u_char *cmd, int len)
+{
+ struct ibfoo *ib;
+
+ ib = u->ibfoo;
+
+ if (ib->rdh != NULL || ib->wrh != NULL) {
+ upd7210_take_ctrl_async(u);
+ ib->rdh = NULL;
+ ib->wrh = NULL;
+ }
+ mtx_lock(&u->mutex);
+ ib->mode = PIO_CMD;
+ ib->buf = cmd;
+ ib->buflen = len;
+ upd7210_wr(u, IMR2, IXR2_CO);
+
+ gpib_ib_irq(u, 1);
+
+ gpib_ib_wait_xfer(u, ib);
+
+ mtx_unlock(&u->mutex);
+ return (len - ib->buflen);
+}
+
+static int
+pio_odata(struct upd7210 *u, u_char *data, int len)
+{
+ struct ibfoo *ib;
+
+ ib = u->ibfoo;
+
+ if (len == 0)
+ return (0);
+ mtx_lock(&u->mutex);
+ ib->mode = PIO_ODATA;
+ ib->buf = data;
+ ib->buflen = len;
+ upd7210_wr(u, IMR1, IXR1_DO);
+
+ gpib_ib_wait_xfer(u, ib);
+
+ mtx_unlock(&u->mutex);
+ return (len - ib->buflen);
+}
+
+static int
+pio_idata(struct upd7210 *u, u_char *data, int len)
+{
+ struct ibfoo *ib;
+
+ ib = u->ibfoo;
+
+ mtx_lock(&u->mutex);
+ ib->mode = PIO_IDATA;
+ ib->buf = data;
+ ib->buflen = len;
+ upd7210_wr(u, IMR1, IXR1_DI);
+
+ gpib_ib_wait_xfer(u, ib);
+
+ mtx_unlock(&u->mutex);
+ return (len - ib->buflen);
+}
+
+static int
+dma_idata(struct upd7210 *u, u_char *data, int len)
+{
+ int j;
+ struct ibfoo *ib;
+
+ KASSERT(u->dmachan >= 0, ("Bogus dmachan %d", u->dmachan));
+ ib = u->ibfoo;
+ ib->mode = DMA_IDATA;
+ mtx_lock(&Giant);
+ isa_dmastart(ISADMA_READ, data, len, u->dmachan);
+ mtx_unlock(&Giant);
+ mtx_lock(&u->mutex);
+ upd7210_wr(u, IMR1, IXR1_ENDRX);
+ upd7210_wr(u, IMR2, IMR2_DMAI);
+ gpib_ib_wait_xfer(u, ib);
+ mtx_unlock(&u->mutex);
+ mtx_lock(&Giant);
+ j = isa_dmastatus(u->dmachan);
+ isa_dmadone(ISADMA_READ, data, len, u->dmachan);
+ mtx_unlock(&Giant);
+ return (len - j);
+}
+
+static int
+ib_send_msg(struct ibfoo *ib, int msg)
+{
+ u_char buf[10];
+ int i, j;
+
+ i = 0;
+ buf[i++] = UNT;
+ buf[i++] = UNL;
+ buf[i++] = LAD | ib->h->pad;
+ if (ib->h->sad)
+ buf[i++] = LAD | TAD | ib->h->sad;
+ buf[i++] = TAD | 0;
+ buf[i++] = msg;
+ j = pio_cmd(ib->u, buf, i);
+ if (i != j)
+ ib_set_error(ib->ap, EABO); /* XXX ? */
+ return (0);
+}
+
+static int
+ibask(struct ibfoo *ib)
+{ /* XXX */
+
+ ibdebug = ib->ap->option;
+ return (0);
+}
+
+#define ibbna NULL
+#define ibcac NULL
+
+static int
+ibclr(struct ibfoo *ib)
+{
+
+ return (ib_send_msg(ib, SDC));
+}
+
+#define ibcmd NULL
+#define ibcmda NULL
+#define ibconfig NULL
+
+static int
+ibdev(struct ibfoo *ib)
+{ /* TBD */
+ struct handle *h;
+
+ h = malloc(sizeof *h, M_IBFOO, M_ZERO | M_WAITOK);
+ h->handle = alloc_unr(ib->unrhdr);
+ h->kind = H_DEV;
+ h->pad = ib->ap->pad;
+ h->sad = ib->ap->sad;
+ h->timeout = timeouts[ib->ap->tmo];
+ h->eot = ib->ap->eot;
+ h->eos = ib->ap->eos;
+ mtx_lock(&ib->u->mutex);
+ LIST_INSERT_HEAD(&ib->handles, h, list);
+ mtx_unlock(&ib->u->mutex);
+ ib->ap->__retval = h->handle;
+ return (0);
+}
+
+#define ibdiag NULL
+
+static int
+ibdma(struct ibfoo *ib)
+{
+
+ if (ib->u->dmachan < 0 && ib->ap->v)
+ return (ib_set_error(ib->ap, EARG));
+ ib->h->dma = ib->ap->v;
+ return (0);
+}
+
+static int
+ibeos(struct ibfoo *ib)
+{
+
+ ib->ap->__iberr = ib->h->eos;
+ ib->h->eos = ib->ap->eos;
+ if (ib->rdh == ib->h)
+ config_eos(ib->u, ib->h);
+ return (0);
+}
+
+static int
+ibeot(struct ibfoo *ib)
+{
+
+ ib->h->eot = ib->ap->eot;
+ return (0);
+}
+
+#define ibevent NULL
+#define ibfind NULL
+#define ibgts NULL
+#define ibist NULL
+#define iblines NULL
+#define ibllo NULL
+#define ibln NULL
+
+static int
+ibloc(struct ibfoo *ib)
+{ /* XXX */
+
+ if (ib->h->kind == H_BOARD)
+ return (EOPNOTSUPP); /* XXX */
+ return (ib_send_msg(ib, GTL));
+}
+
+static int
+ibonl(struct ibfoo *ib)
+{ /* XXX */
+
+ if (ib->ap->v)
+ return (EOPNOTSUPP); /* XXX */
+ mtx_lock(&ib->u->mutex);
+ LIST_REMOVE(ib->h, list);
+ mtx_unlock(&ib->u->mutex);
+ free(ib->h, M_IBFOO);
+ ib->h = NULL;
+ return (0);
+}
+
+static int
+ibpad(struct ibfoo *ib)
+{
+
+ ib->h->pad = ib->ap->pad;
+ return (0);
+}
+
+#define ibpct NULL
+#define ibpoke NULL
+#define ibppc NULL
+
+static int
+ibrd(struct ibfoo *ib)
+{ /* TBD */
+ u_char buf[10], *bp;
+ int i, j, error, bl, bc;
+ u_char *dp;
+
+ if (ib->h->kind == H_BOARD)
+ return (EOPNOTSUPP); /* XXX */
+ bl = ib->ap->cnt;
+ if (bl > PAGE_SIZE)
+ bl = PAGE_SIZE;
+ bp = malloc(bl, M_IBFOO, M_WAITOK);
+
+ if (ib->rdh != ib->h) {
+ i = 0;
+ buf[i++] = UNT;
+ buf[i++] = UNL;
+ buf[i++] = LAD | 0;
+ buf[i++] = TAD | ib->h->pad;
+ if (ib->h->sad)
+ buf[i++] = ib->h->sad;
+ i = pio_cmd(ib->u, buf, i);
+ config_eos(ib->u, ib->h);
+ ib->rdh = ib->h;
+ ib->wrh = NULL;
+ }
+ upd7210_goto_standby(ib->u);
+ dp = ib->ap->buffer;
+ bc = ib->ap->cnt;
+ error = 0;
+ while (bc > 0 && ib->ap->__iberr == 0) {
+ j = imin(bc, PAGE_SIZE);
+ if (ib->h->dma)
+ i = dma_idata(ib->u, bp, j);
+ else
+ i = pio_idata(ib->u, bp, j);
+ error = copyout(bp, dp , i);
+ if (error)
+ break;
+ ib->ap->__ibcnt += i;
+ if (i != j)
+ break;
+ bc -= i;
+ dp += i;
+ }
+ upd7210_take_ctrl_async(ib->u);
+ free(bp, M_IBFOO);
+ return (error);
+}
+
+#define ibrda NULL
+#define ibrdf NULL
+#define ibrdkey NULL
+#define ibrpp NULL
+#define ibrsc NULL
+#define ibrsp NULL
+#define ibrsv NULL
+
+static int
+ibsad(struct ibfoo *ib)
+{
+
+ ib->h->sad = ib->ap->sad;
+ return (0);
+}
+
+#define ibsgnl NULL
+
+static int
+ibsic(struct ibfoo *ib)
+{ /* TBD */
+
+ upd7210_wr(ib->u, AUXMR, AUXMR_SIFC);
+ DELAY(100);
+ upd7210_wr(ib->u, AUXMR, AUXMR_CIFC);
+ return (0);
+}
+
+#define ibsre NULL
+#define ibsrq NULL
+#define ibstop NULL
+
+static int
+ibtmo(struct ibfoo *ib)
+{
+
+ ib->h->timeout = timeouts[ib->ap->tmo];
+ return (0);
+}
+
+#define ibtrap NULL
+
+static int
+ibtrg(struct ibfoo *ib)
+{
+
+ return (ib_send_msg(ib, GET));
+}
+
+#define ibwait NULL
+
+static int
+ibwrt(struct ibfoo *ib)
+{ /* XXX */
+ u_char buf[10], *bp;
+ int i;
+
+ if (ib->h->kind == H_BOARD)
+ return (EOPNOTSUPP);
+ bp = malloc(ib->ap->cnt, M_IBFOO, M_WAITOK);
+ /* XXX: bigger than PAGE_SIZE handling */
+ i = copyin(ib->ap->buffer, bp, ib->ap->cnt);
+ if (i) {
+ free(bp, M_IBFOO);
+ return (i);
+ }
+ if (ib->wrh != ib->h) {
+ i = 0;
+ buf[i++] = UNT;
+ buf[i++] = UNL;
+ buf[i++] = LAD | ib->h->pad;
+ if (ib->h->sad)
+ buf[i++] = LAD | TAD | ib->h->sad;
+ buf[i++] = TAD | 0;
+ i = pio_cmd(ib->u, buf, i);
+ ib->rdh = NULL;
+ ib->wrh = ib->h;
+ config_eos(ib->u, ib->h);
+ }
+ upd7210_goto_standby(ib->u);
+ ib->doeoi = ib->h->eot;
+ i = pio_odata(ib->u, bp, ib->ap->cnt);
+ upd7210_take_ctrl_async(ib->u);
+ ib->ap->__ibcnt = i;
+ free(bp, M_IBFOO);
+ return (0);
+}
+
+#define ibwrta NULL
+#define ibwrtf NULL
+#define ibwrtkey NULL
+#define ibxtrc NULL
+
+static struct ibhandler {
+ const char *name;
+ enum h_kind kind;
+ ibhandler_t *func;
+ u_int args;
+} ibhandlers[] = {
+ [__ID_IBASK] = { "ibask", H_EITHER, ibask, __F_HANDLE | __F_OPTION | __F_RETVAL },
+ [__ID_IBBNA] = { "ibbna", H_DEV, ibbna, __F_HANDLE | __F_BDNAME },
+ [__ID_IBCAC] = { "ibcac", H_BOARD, ibcac, __F_HANDLE | __F_V },
+ [__ID_IBCLR] = { "ibclr", H_DEV, ibclr, __F_HANDLE },
+ [__ID_IBCMD] = { "ibcmd", H_BOARD, ibcmd, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBCMDA] = { "ibcmda", H_BOARD, ibcmda, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBCONFIG] = { "ibconfig", H_EITHER, ibconfig, __F_HANDLE | __F_OPTION | __F_VALUE },
+ [__ID_IBDEV] = { "ibdev", 0, ibdev, __F_BOARDID | __F_PAD | __F_SAD | __F_TMO | __F_EOT | __F_EOS },
+ [__ID_IBDIAG] = { "ibdiag", H_EITHER, ibdiag, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBDMA] = { "ibdma", H_EITHER, ibdma, __F_HANDLE | __F_V },
+ [__ID_IBEOS] = { "ibeos", H_EITHER, ibeos, __F_HANDLE | __F_EOS },
+ [__ID_IBEOT] = { "ibeot", H_EITHER, ibeot, __F_HANDLE | __F_EOT },
+ [__ID_IBEVENT] = { "ibevent", H_BOARD, ibevent, __F_HANDLE | __F_EVENT },
+ [__ID_IBFIND] = { "ibfind", 0, ibfind, __F_BDNAME },
+ [__ID_IBGTS] = { "ibgts", H_BOARD, ibgts, __F_HANDLE | __F_V },
+ [__ID_IBIST] = { "ibist", H_BOARD, ibist, __F_HANDLE | __F_V },
+ [__ID_IBLINES] = { "iblines", H_BOARD, iblines, __F_HANDLE | __F_LINES },
+ [__ID_IBLLO] = { "ibllo", H_EITHER, ibllo, __F_HANDLE },
+ [__ID_IBLN] = { "ibln", H_BOARD, ibln, __F_HANDLE | __F_PADVAL | __F_SADVAL | __F_LISTENFLAG },
+ [__ID_IBLOC] = { "ibloc", H_EITHER, ibloc, __F_HANDLE },
+ [__ID_IBONL] = { "ibonl", H_EITHER, ibonl, __F_HANDLE | __F_V },
+ [__ID_IBPAD] = { "ibpad", H_EITHER, ibpad, __F_HANDLE | __F_PAD },
+ [__ID_IBPCT] = { "ibpct", H_DEV, ibpct, __F_HANDLE },
+ [__ID_IBPOKE] = { "ibpoke", H_EITHER, ibpoke, __F_HANDLE | __F_OPTION | __F_VALUE },
+ [__ID_IBPPC] = { "ibppc", H_EITHER, ibppc, __F_HANDLE | __F_V },
+ [__ID_IBRD] = { "ibrd", H_EITHER, ibrd, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBRDA] = { "ibrda", H_EITHER, ibrda, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBRDF] = { "ibrdf", H_EITHER, ibrdf, __F_HANDLE | __F_FLNAME },
+ [__ID_IBRDKEY] = { "ibrdkey", H_EITHER, ibrdkey, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBRPP] = { "ibrpp", H_EITHER, ibrpp, __F_HANDLE | __F_PPR },
+ [__ID_IBRSC] = { "ibrsc", H_BOARD, ibrsc, __F_HANDLE | __F_V },
+ [__ID_IBRSP] = { "ibrsp", H_DEV, ibrsp, __F_HANDLE | __F_SPR },
+ [__ID_IBRSV] = { "ibrsv", H_EITHER, ibrsv, __F_HANDLE | __F_V },
+ [__ID_IBSAD] = { "ibsad", H_EITHER, ibsad, __F_HANDLE | __F_SAD },
+ [__ID_IBSGNL] = { "ibsgnl", H_EITHER, ibsgnl, __F_HANDLE | __F_V },
+ [__ID_IBSIC] = { "ibsic", H_BOARD, ibsic, __F_HANDLE },
+ [__ID_IBSRE] = { "ibsre", H_BOARD, ibsre, __F_HANDLE | __F_V },
+ [__ID_IBSRQ] = { "ibsrq", H_EITHER, ibsrq, __F_FUNC },
+ [__ID_IBSTOP] = { "ibstop", H_EITHER, ibstop, __F_HANDLE },
+ [__ID_IBTMO] = { "ibtmo", H_EITHER, ibtmo, __F_HANDLE | __F_TMO },
+ [__ID_IBTRAP] = { "ibtrap", H_EITHER, ibtrap, __F_MASK | __F_MODE },
+ [__ID_IBTRG] = { "ibtrg", H_DEV, ibtrg, __F_HANDLE },
+ [__ID_IBWAIT] = { "ibwait", H_EITHER, ibwait, __F_HANDLE | __F_MASK },
+ [__ID_IBWRT] = { "ibwrt", H_EITHER, ibwrt, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBWRTA] = { "ibwrta", H_EITHER, ibwrta, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBWRTF] = { "ibwrtf", H_EITHER, ibwrtf, __F_HANDLE | __F_FLNAME },
+ [__ID_IBWRTKEY] = { "ibwrtkey", H_EITHER, ibwrtkey, __F_HANDLE | __F_BUFFER | __F_CNT },
+ [__ID_IBXTRC] = { "ibxtrc", H_EITHER, ibxtrc, __F_HANDLE | __F_BUFFER | __F_CNT },
+};
+
+static const u_int max_ibhandler = sizeof ibhandlers / sizeof ibhandlers[0];
+
+static void
+ib_dump_args(struct ibhandler *ih, struct ibarg *ap)
+{
+
+ if (ih->name != NULL)
+ printf("%s(", ih->name);
+ else
+ printf("ibinvalid(");
+ printf("[0x%x]", ap->__field);
+ if (ap->__field & __F_HANDLE) printf(" handle=%d", ap->handle);
+ if (ap->__field & __F_EOS) printf(" eos=0x%x", ap->eos);
+ if (ap->__field & __F_EOT) printf(" eot=%d", ap->eot);
+ if (ap->__field & __F_TMO) printf(" tmo=%d", ap->tmo);
+ if (ap->__field & __F_PAD) printf(" pad=0x%x", ap->pad);
+ if (ap->__field & __F_SAD) printf(" sad=0x%x", ap->sad);
+ if (ap->__field & __F_BUFFER) printf(" buffer=%p", ap->buffer);
+ if (ap->__field & __F_CNT) printf(" cnt=%ld", ap->cnt);
+ if (ap->__field & __F_V) printf(" v=%d/0x%x", ap->v, ap->v);
+ /* XXX more ... */
+ printf(")\n");
+}
+
+static int
+gpib_ib_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct upd7210 *u;
+ struct ibfoo *ib;
+ int error = 0;
+
+ u = dev->si_drv1;
+
+ mtx_lock(&u->mutex);
+ if (u->busy) {
+ mtx_unlock(&u->mutex);
+ return (EBUSY);
+ }
+ u->busy = 1;
+ mtx_unlock(&u->mutex);
+
+ if (u->dmachan >= 0) {
+ mtx_lock(&Giant);
+ error = isa_dma_acquire(u->dmachan);
+ if (!error) {
+ error = isa_dma_init(u->dmachan, PAGE_SIZE, M_WAITOK);
+ if (error)
+ isa_dma_release(u->dmachan);
+ }
+ mtx_unlock(&Giant);
+ }
+
+ if (error) {
+ mtx_lock(&u->mutex);
+ u->busy = 0;
+ mtx_unlock(&u->mutex);
+ return (error);
+ }
+
+ ib = malloc(sizeof *ib, M_IBFOO, M_WAITOK | M_ZERO);
+ LIST_INIT(&ib->handles);
+ callout_init(&ib->callout, 1);
+ ib->unrhdr = new_unrhdr(0, INT_MAX, NULL);
+ dev->si_drv2 = ib;
+ ib->u = u;
+ u->ibfoo = ib;
+ u->irq = gpib_ib_irq;
+
+ upd7210_wr(u, AUXMR, AUXMR_CRST);
+ DELAY(10000);
+ DELAY(1000);
+ upd7210_wr(u, IMR1, 0x00);
+ upd7210_wr(u, IMR2, 0x00);
+ upd7210_wr(u, SPMR, 0x00);
+ upd7210_wr(u, ADR, 0x00);
+ upd7210_wr(u, ADR, ADR_ARS | ADR_DL | ADR_DT);
+ upd7210_wr(u, ADMR, ADMR_ADM0 | ADMR_TRM0 | ADMR_TRM1);
+ upd7210_wr(u, EOSR, 0x00);
+ upd7210_wr(u, AUXMR, C_ICR | 8);
+ upd7210_wr(u, AUXMR, C_PPR | PPR_U);
+ upd7210_wr(u, AUXMR, C_AUXA);
+ upd7210_wr(u, AUXMR, C_AUXB + 3);
+ upd7210_wr(u, AUXMR, C_AUXE + 0);
+ upd7210_wr(u, AUXMR, AUXMR_PON);
+ upd7210_wr(u, AUXMR, AUXMR_CIFC);
+ DELAY(100);
+ upd7210_wr(u, AUXMR, AUXMR_SIFC);
+ upd7210_wr(u, AUXMR, AUXMR_SREN);
+ return (0);
+}
+
+static int
+gpib_ib_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct upd7210 *u;
+ struct ibfoo *ib;
+
+ u = dev->si_drv1;
+ ib = dev->si_drv2;
+ /* XXX: assert pointer consistency */
+
+ u->ibfoo = NULL;
+ /* XXX: free handles */
+ dev->si_drv2 = NULL;
+ free(ib, M_IBFOO);
+
+ if (u->dmachan >= 0) {
+ mtx_lock(&Giant);
+ isa_dma_release(u->dmachan);
+ mtx_unlock(&Giant);
+ }
+ mtx_lock(&u->mutex);
+ u->busy = 0;
+ ibdebug = 0;
+ upd7210_wr(u, IMR1, 0x00);
+ upd7210_wr(u, IMR2, 0x00);
+ upd7210_wr(u, AUXMR, AUXMR_CRST);
+ DELAY(10000);
+ mtx_unlock(&u->mutex);
+ return (0);
+}
+
+static int
+gpib_ib_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ struct ibarg *ap;
+ struct ibhandler *ih;
+ struct handle *h;
+ struct upd7210 *u;
+ struct ibfoo *ib;
+ int error;
+ struct timeval deadline, tv;
+
+ u = dev->si_drv1;
+ ib = u->ibfoo;
+
+ /* We only support a single ioctl, everything else is a mistake */
+ if (cmd != GPIB_IBFOO)
+ return (ENOIOCTL);
+
+ /* Check the identifier and field-bitmap in the arguments. */
+ ap = (void *)data;
+ if (ap->__ident < 0 || ap->__ident >= max_ibhandler)
+ return (EINVAL);
+ ih = &ibhandlers[ap->__ident];
+ if (ap->__field != ih->args)
+ return (EINVAL);
+
+ if (ibdebug)
+ ib_dump_args(ih, ap);
+
+ if (ih->func == NULL)
+ return (EOPNOTSUPP);
+
+ ap->__iberr = 0;
+ ap->__ibsta = 0;
+ ap->__ibcnt = 0;
+ ap->retval = 0;
+
+ if (ap->__field & __F_TMO) {
+ if (ap->tmo < 0 || ap->tmo >= max_timeouts)
+ return (ib_set_error(ap, EARG));
+ }
+
+ if (ap->__field & __F_EOS) {
+ if ((ap->eos & ~(REOS | XEOS | BIN | 0xff)) ||
+ ((ap->eos & (BIN | 0x80)) == 0x80))
+ return (ib_set_error(ap, EARG));
+ }
+ if (ap->__field & __F_PAD) {
+ if (ap->pad < 0 || ap->pad > 30)
+ return (ib_set_error(ap, EARG));
+ }
+ if (ap->__field & __F_SAD) {
+ if (ap->sad != 0 && (ap->sad < 0x60 || ap->sad > 126))
+ return (ib_set_error(ap, EARG));
+ }
+
+
+ mtx_lock(&u->mutex);
+
+
+ /* Find the handle, if any */
+ h = NULL;
+ if ((ap->__field & __F_HANDLE) && gethandle(u, ap, &h)) {
+ mtx_unlock(&u->mutex);
+ return (0);
+ }
+
+ /* Check that the handle is the right kind */
+ if (h != NULL && !(h->kind & ih->kind)) {
+ mtx_unlock(&u->mutex);
+ return (ib_set_error(ap, EARG));
+ }
+
+ /* Set up handle and deadline */
+ if (h != NULL && timevalisset(&h->timeout)) {
+ getmicrouptime(&deadline);
+ timevaladd(&deadline, &h->timeout);
+ } else {
+ timevalclear(&deadline);
+ }
+
+ /* Wait for the card to be(come) available, respect deadline */
+ while(u->busy != 1) {
+ error = msleep(ib, &u->mutex,
+ PZERO | PCATCH, "gpib_ibioctl", hz / 10);
+ if (error == 0)
+ continue;
+ mtx_unlock(&u->mutex);
+ if (error == EINTR)
+ return(ib_set_error(ap, EABO));
+ if (error == EWOULDBLOCK && timevalisset(&deadline)) {
+ getmicrouptime(&tv);
+ if (timevalcmp(&deadline, &tv, <))
+ return(ib_had_timeout(ap));
+ }
+ mtx_lock(&u->mutex);
+ }
+ u->busy = 2;
+ mtx_unlock(&u->mutex);
+
+ /* Hand over deadline handling to the callout routine */
+ ib->ap = ap;
+ ib->h = h;
+ ib->mode = BUSY;
+ ib->deadline = deadline;
+ callout_reset(&ib->callout, hz / 5, gpib_ib_timeout, u);
+
+ error = ih->func(ib);
+
+ /* Release card */
+ ib->mode = IDLE;
+ ib->ap = NULL;
+ ib->h = NULL;
+ timevalclear(&deadline);
+ callout_stop(&ib->callout);
+
+ mtx_lock(&u->mutex);
+ u->busy = 1;
+ wakeup(ib);
+ mtx_unlock(&u->mutex);
+
+ if (error)
+ return(ib_set_errno(ap, error));
+ return (0);
+}
+
+struct cdevsw gpib_ib_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "gpib_ib",
+ .d_open = gpib_ib_open,
+ .d_ioctl = gpib_ib_ioctl,
+ .d_close = gpib_ib_close,
+};
diff --git a/sys/dev/ieee488/ibfoo_int.h b/sys/dev/ieee488/ibfoo_int.h
new file mode 100644
index 000000000000..28f72897a9df
--- /dev/null
+++ b/sys/dev/ieee488/ibfoo_int.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file defines the ABI between the userland gpib library and the
+ * kernel. This file should not be used anywhere else.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/ioccom.h>
+
+typedef void ibsrq_t(void);
+enum ibfoo_id {
+ __ID_INVALID = 0,
+ __ID_IBASK,
+ __ID_IBBNA,
+ __ID_IBCAC,
+ __ID_IBCLR,
+ __ID_IBCMD,
+ __ID_IBCMDA,
+ __ID_IBCONFIG,
+ __ID_IBDEV,
+ __ID_IBDIAG,
+ __ID_IBDMA,
+ __ID_IBEOS,
+ __ID_IBEOT,
+ __ID_IBEVENT,
+ __ID_IBFIND,
+ __ID_IBGTS,
+ __ID_IBIST,
+ __ID_IBLINES,
+ __ID_IBLLO,
+ __ID_IBLN,
+ __ID_IBLOC,
+ __ID_IBONL,
+ __ID_IBPAD,
+ __ID_IBPCT,
+ __ID_IBPOKE,
+ __ID_IBPPC,
+ __ID_IBRD,
+ __ID_IBRDA,
+ __ID_IBRDF,
+ __ID_IBRDKEY,
+ __ID_IBRPP,
+ __ID_IBRSC,
+ __ID_IBRSP,
+ __ID_IBRSV,
+ __ID_IBSAD,
+ __ID_IBSGNL,
+ __ID_IBSIC,
+ __ID_IBSRE,
+ __ID_IBSRQ,
+ __ID_IBSTOP,
+ __ID_IBTMO,
+ __ID_IBTRAP,
+ __ID_IBTRG,
+ __ID_IBWAIT,
+ __ID_IBWRT,
+ __ID_IBWRTA,
+ __ID_IBWRTF,
+ __ID_IBWRTKEY,
+ __ID_IBXTRC
+};
+
+#define __F_HANDLE (1 << 0)
+#define __F_SPR (1 << 1)
+#define __F_BUFFER (1 << 2)
+#define __F_RETVAL (1 << 3)
+#define __F_BDNAME (1 << 4)
+#define __F_MASK (1 << 5)
+#define __F_PADVAL (1 << 6)
+#define __F_SADVAL (1 << 7)
+#define __F_CNT (1 << 8)
+#define __F_TMO (1 << 9)
+#define __F_EOS (1 << 10)
+#define __F_PPR (1 << 11)
+#define __F_EOT (1 << 12)
+#define __F_V (1 << 13)
+#define __F_VALUE (1 << 14)
+#define __F_SAD (1 << 15)
+#define __F_BOARDID (1 << 16)
+#define __F_OPTION (1 << 17)
+#define __F_FLNAME (1 << 18)
+#define __F_FUNC (1 << 19)
+#define __F_LINES (1 << 20)
+#define __F_PAD (1 << 21)
+#define __F_MODE (1 << 22)
+#define __F_LISTENFLAG (1 << 23)
+#define __F_EVENT (1 << 24)
+
+struct ibarg {
+ enum ibfoo_id __ident;
+ unsigned int __field;
+ int __retval;
+ int __ibsta;
+ int __iberr;
+ int __ibcnt;
+ int handle;
+ char * spr;
+ void * buffer;
+ int * retval;
+ char * bdname;
+ int mask;
+ int padval;
+ int sadval;
+ long cnt;
+ int tmo;
+ int eos;
+ char * ppr;
+ int eot;
+ int v;
+ int value;
+ int sad;
+ int boardID;
+ int option;
+ char * flname;
+ ibsrq_t * func;
+ short * lines;
+ int pad;
+ int mode;
+ short * listenflag;
+ short * event;
+};
+
+#define GPIB_IBFOO _IOWR(4, 0, struct ibarg)
diff --git a/sys/dev/ieee488/pcii.c b/sys/dev/ieee488/pcii.c
new file mode 100644
index 000000000000..d575f6927d59
--- /dev/null
+++ b/sys/dev/ieee488/pcii.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Driver for GPIB cards based on NEC µPD7210 and compatibles.
+ *
+ * This driver just hooks up to the hardware and leaves all the interesting
+ * stuff to upd7210.c.
+ *
+ * Supported hardware:
+ * PCIIA compatible cards.
+ *
+ * Tested and known working:
+ * "B&C Microsystems PC488A-0"
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+#include <isa/isavar.h>
+
+#define UPD7210_HW_DRIVER
+#include <dev/ieee488/upd7210.h>
+
+struct pcii_softc {
+ int foo;
+ struct resource *port[8];
+ struct resource *irq;
+ struct resource *dma;
+ void *intr_handler;
+ struct upd7210 upd7210;
+};
+
+static devclass_t pcii_devclass;
+
+static int pcii_probe(device_t dev);
+static int pcii_attach(device_t dev);
+
+static device_method_t pcii_methods[] = {
+ DEVMETHOD(device_probe, pcii_probe),
+ DEVMETHOD(device_attach, pcii_attach),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ { 0, 0 }
+};
+
+static driver_t pcii_driver = {
+ "pcii",
+ pcii_methods,
+ sizeof(struct pcii_softc),
+};
+
+static int
+pcii_probe(device_t dev)
+{
+ struct resource *port;
+ int rid;
+ u_long start, count;
+ int i, j, error = 0;
+
+ device_set_desc(dev, "PCII IEEE-4888 controller");
+
+ rid = 0;
+ if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
+ return ENXIO;
+ if ((start & 0x3ff) != 0x2e1)
+ return (ENXIO);
+ count = 1;
+ if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
+ return ENXIO;
+ for (i = 0; i < 8; i++) {
+ j = bus_set_resource(dev, SYS_RES_IOPORT, i,
+ start + 0x400 * i, 1);
+ if (j) {
+ error = ENXIO;
+ break;
+ }
+ rid = i;
+ port = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
+ &rid, RF_ACTIVE);
+ if (port == NULL)
+ return (ENXIO);
+ else
+ bus_release_resource(dev, SYS_RES_IOPORT, i, port);
+ }
+
+ rid = 0;
+ port = bus_alloc_resource_any(dev,
+ SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
+ if (port == NULL)
+ return (ENXIO);
+ bus_release_resource(dev, SYS_RES_IRQ, rid, port);
+
+ return (error);
+}
+
+static int
+pcii_attach(device_t dev)
+{
+ struct pcii_softc *sc;
+ int unit;
+ int rid;
+ int i, error = 0;
+
+ unit = device_get_unit(dev);
+ sc = device_get_softc(dev);
+ memset(sc, 0, sizeof *sc);
+
+ device_set_desc(dev, "PCII IEEE-4888 controller");
+
+ for (rid = 0; rid < 8; rid++) {
+ sc->port[rid] = bus_alloc_resource_any(dev,
+ SYS_RES_IOPORT, &rid, RF_ACTIVE);
+ if (sc->port[rid] == NULL) {
+ error = ENXIO;
+ break;
+ }
+ sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]);
+ sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]);
+ }
+ if (!error) {
+ rid = 0;
+ sc->irq = bus_alloc_resource_any(dev,
+ SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
+ if (sc->irq == NULL) {
+ error = ENXIO;
+ } else {
+ error = bus_setup_intr(dev, sc->irq,
+ INTR_TYPE_MISC | INTR_MPSAFE,
+ upd7210intr, &sc->upd7210, &sc->intr_handler);
+ }
+ }
+ if (!error) {
+ rid = 0;
+ sc->dma = bus_alloc_resource_any(dev,
+ SYS_RES_DRQ, &rid, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->dma == NULL)
+ sc->upd7210.dmachan = -1;
+ else
+ sc->upd7210.dmachan = rman_get_start(sc->dma);
+ }
+ if (error) {
+ for (i = 0; i < 8; i++) {
+ if (sc->port[i] == NULL)
+ break;
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ 0, sc->port[i]);
+ }
+ if (sc->intr_handler != NULL)
+ bus_teardown_intr(dev, sc->irq, sc->intr_handler);
+ if (sc->irq != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq);
+ }
+ upd7210attach(&sc->upd7210);
+ return (error);
+}
+
+DRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
+DRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);
diff --git a/sys/dev/ieee488/ugpib.h b/sys/dev/ieee488/ugpib.h
new file mode 100644
index 000000000000..726a70219dd8
--- /dev/null
+++ b/sys/dev/ieee488/ugpib.h
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _DEV_IEEE488_UGPIB_H_
+#define _DEV_IEEE488_UGPIB_H_
+
+/* ibfoo() return values */
+#define EDVR 0 /* System error */
+#define ECIC 1 /* Not Active Controller */
+#define ENOL 2 /* Nobody listening */
+#define EADR 3 /* Controller not addressed */
+#define EARG 4 /* Invalid argument */
+#define ESAC 5 /* Not System Controller */
+#define EABO 6 /* I/O Aborted/Time out */
+#define ENEB 7 /* No such controller */
+#define EOIP 10 /* Async I/O in progress */
+#define ECAP 11 /* No such capability */
+#define EFSO 12 /* File system error */
+#define EBUS 14 /* Command byte xfer error */
+#define ESTB 15 /* Serial poll status byte lost */
+#define ESRQ 16 /* SRQ line stuck */
+#define ETAB 20 /* Table problem */
+
+/* ibsta bits */
+#define ERR (1<<15) /* Error */
+#define TIMO (1<<14) /* Timeout */
+#define END (1<<13) /* EOI/EOS */
+#define SRQI (1<<12) /* SRQ */
+#define RQS (1<<11) /* Device requests service */
+#define SPOLL (1<<10) /* Serial Poll */
+#define EVENT (1<<9) /* Event occured */
+#define CMPL (1<<8) /* I/O complete */
+#define LOK (1<<7) /* Lockout */
+#define REM (1<<6) /* Remote */
+#define CIC (1<<5) /* CIC */
+#define ATN (1<<4) /* ATN */
+#define TACS (1<<3) /* Talker */
+#define LACS (1<<2) /* Listener */
+#define DTAS (1<<1) /* Device trigger status */
+#define DCAS (1<<0) /* Device clear state */
+
+/* Timeouts */
+#define TNONE 0
+#define T10us 1
+#define T30us 2
+#define T100us 3
+#define T300us 4
+#define T1ms 5
+#define T3ms 6
+#define T10ms 7
+#define T30ms 8
+#define T100ms 9
+#define T300ms 10
+#define T1s 11
+#define T3s 12
+#define T10s 13
+#define T30s 14
+#define T100s 15
+#define T300s 16
+#define T1000s 17
+
+/* EOS bits */
+#define REOS (1 << 10)
+#define XEOS (1 << 11)
+#define BIN (1 << 12)
+
+/* Bus commands */
+#define GTL 0x01 /* Go To Local */
+#define SDC 0x04 /* Selected Device Clear */
+#define GET 0x08 /* Group Execute Trigger */
+#define LAD 0x20 /* Listen address */
+#define UNL 0x3F /* Unlisten */
+#define TAD 0x40 /* Talk address */
+#define UNT 0x5F /* Untalk */
+
+#ifndef _KERNEL
+
+extern int ibcnt, iberr, ibsta;
+
+int ibask(int handle, int option, int *retval);
+int ibbna(int handle, char *bdname);
+int ibcac(int handle, int v);
+int ibclr(int handle);
+int ibcmd(int handle, void *buffer, long cnt);
+int ibcmda(int handle, void *buffer, long cnt);
+int ibconfig(int handle, int option, int value);
+int ibdev(int boardID, int pad, int sad, int tmo, int eot, int eos);
+int ibdiag(int handle, void *buffer, long cnt);
+int ibdma(int handle, int v);
+int ibeos(int handle, int eos);
+int ibeot(int handle, int eot);
+int ibevent(int handle, short *event);
+int ibfind(char *bdname);
+int ibgts(int handle, int v);
+int ibist(int handle, int v);
+int iblines(int handle, short *lines);
+int ibllo(int handle);
+int ibln(int handle, int padval, int sadval, short *listenflag);
+int ibloc(int handle);
+int ibonl(int handle, int v);
+int ibpad(int handle, int pad);
+int ibpct(int handle);
+int ibpoke(int handle, int option, int value);
+int ibppc(int handle, int v);
+int ibrd(int handle, void *buffer, long cnt);
+int ibrda(int handle, void *buffer, long cnt);
+int ibrdf(int handle, char *flname);
+int ibrdkey(int handle, void *buffer, int cnt);
+int ibrpp(int handle, char *ppr);
+int ibrsc(int handle, int v);
+int ibrsp(int handle, char *spr);
+int ibrsv(int handle, int v);
+int ibsad(int handle, int sad);
+int ibsgnl(int handle, int v);
+int ibsic(int handle);
+int ibsre(int handle, int v);
+int ibsrq(void (*func)(void));
+int ibstop(int handle);
+int ibtmo(int handle, int tmo);
+int ibtrap(int mask, int mode);
+int ibtrg(int handle);
+int ibwait(int handle, int mask);
+int ibwrt(int handle, const void *buffer, long cnt);
+int ibwrta(int handle, const void *buffer, long cnt);
+int ibwrtf(int handle, const char *flname);
+int ibwrtkey(int handle, const void *buffer, int cnt);
+int ibxtrc(int handle, void *buffer, long cnt);
+#endif /* _KERNEL */
+#endif /* _DEV_IEEE488_UGPIB_H_ */
diff --git a/sys/dev/ieee488/upd7210.c b/sys/dev/ieee488/upd7210.c
new file mode 100644
index 000000000000..e4b50ace490a
--- /dev/null
+++ b/sys/dev/ieee488/upd7210.c
@@ -0,0 +1,291 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * High-level driver for µPD7210 based GPIB cards.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+# define GPIB_DEBUG
+# undef GPIB_DEBUG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <isa/isavar.h>
+
+#define UPD7210_HW_DRIVER
+#define UPD7210_SW_DRIVER
+#include <dev/ieee488/upd7210.h>
+
+static MALLOC_DEFINE(M_GPIB, "GPIB", "GPIB");
+
+/* upd7210 generic stuff */
+
+void
+upd7210_print_isr(u_int isr1, u_int isr2)
+{
+ printf("isr1=0x%b isr2=0x%b",
+ isr1, "\20\10CPT\7APT\6DET\5ENDRX\4DEC\3ERR\2DO\1DI",
+ isr2, "\20\10INT\7SRQI\6LOK\5REM\4CO\3LOKC\2REMC\1ADSC");
+}
+
+u_int
+upd7210_rd(struct upd7210 *u, enum upd7210_rreg reg)
+{
+ u_int r;
+
+ r = bus_space_read_1(
+ u->reg_tag[reg],
+ u->reg_handle[reg],
+ u->reg_offset[reg]);
+ u->rreg[reg] = r;
+ return (r);
+}
+
+void
+upd7210_wr(struct upd7210 *u, enum upd7210_wreg reg, u_int val)
+{
+ bus_space_write_1(
+ u->reg_tag[reg],
+ u->reg_handle[reg],
+ u->reg_offset[reg], val);
+ u->wreg[reg] = val;
+ if (reg == AUXMR)
+ u->wreg[8 + (val >> 5)] = val & 0x1f;
+}
+
+void
+upd7210intr(void *arg)
+{
+ u_int isr1, isr2;
+ struct upd7210 *u;
+
+ u = arg;
+ mtx_lock(&u->mutex);
+ isr1 = upd7210_rd(u, ISR1);
+ isr2 = upd7210_rd(u, ISR2);
+ if (u->busy == 0 || u->irq == NULL || !u->irq(u, 1)) {
+ printf("upd7210intr [%02x %02x %02x",
+ upd7210_rd(u, DIR), isr1, isr2);
+ printf(" %02x %02x %02x %02x %02x] ",
+ upd7210_rd(u, SPSR),
+ upd7210_rd(u, ADSR),
+ upd7210_rd(u, CPTR),
+ upd7210_rd(u, ADR0),
+ upd7210_rd(u, ADR1));
+ upd7210_print_isr(isr1, isr2);
+ printf("\n");
+ }
+ mtx_unlock(&u->mutex);
+}
+
+int
+upd7210_take_ctrl_async(struct upd7210 *u)
+{
+ int i;
+
+ upd7210_wr(u, AUXMR, AUXMR_TCA);
+
+ if (!(upd7210_rd(u, ADSR) & ADSR_ATN))
+ return (0);
+ for (i = 0; i < 20; i++) {
+ DELAY(1);
+ if (!(upd7210_rd(u, ADSR) & ADSR_ATN))
+ return (0);
+ }
+ return (1);
+}
+
+int
+upd7210_goto_standby(struct upd7210 *u)
+{
+ int i;
+
+ upd7210_wr(u, AUXMR, AUXMR_GTS);
+
+ if (upd7210_rd(u, ADSR) & ADSR_ATN)
+ return (0);
+ for (i = 0; i < 20; i++) {
+ DELAY(1);
+ if (upd7210_rd(u, ADSR) & ADSR_ATN)
+ return (0);
+ }
+ return (1);
+}
+
+/* Unaddressed Listen Only mode */
+
+static int
+gpib_l_irq(struct upd7210 *u, int intr __unused)
+{
+ int i;
+
+ if (u->rreg[ISR1] & 1) {
+ i = upd7210_rd(u, DIR);
+ u->buf[u->buf_wp++] = i;
+ u->buf_wp &= (u->bufsize - 1);
+ i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1);
+ if (i < 8)
+ upd7210_wr(u, IMR1, 0);
+ wakeup(u->buf);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+gpib_l_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct upd7210 *u;
+
+ u = dev->si_drv1;
+
+ mtx_lock(&u->mutex);
+ if (u->busy) {
+ mtx_unlock(&u->mutex);
+ return (EBUSY);
+ }
+ u->busy = 1;
+ u->irq = gpib_l_irq;
+ mtx_unlock(&u->mutex);
+
+ u->buf = malloc(PAGE_SIZE, M_GPIB, M_WAITOK);
+ u->bufsize = PAGE_SIZE;
+ u->buf_wp = 0;
+ u->buf_rp = 0;
+
+ upd7210_wr(u, AUXMR, AUXMR_CRST);
+ DELAY(10000);
+ upd7210_wr(u, AUXMR, C_ICR | 8);
+ DELAY(1000);
+ upd7210_wr(u, ADR, 0x60);
+ upd7210_wr(u, ADR, 0xe0);
+ upd7210_wr(u, ADMR, 0x70);
+ upd7210_wr(u, AUXMR, AUXMR_PON);
+ upd7210_wr(u, IMR1, 0x01);
+ return (0);
+}
+
+static int
+gpib_l_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct upd7210 *u;
+
+ u = dev->si_drv1;
+
+ mtx_lock(&u->mutex);
+ u->busy = 0;
+ upd7210_wr(u, AUXMR, AUXMR_CRST);
+ DELAY(10000);
+ upd7210_wr(u, IMR1, 0x00);
+ upd7210_wr(u, IMR2, 0x00);
+ free(u->buf, M_GPIB);
+ u->buf = NULL;
+ mtx_unlock(&u->mutex);
+ return (0);
+}
+
+static int
+gpib_l_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct upd7210 *u;
+ int error;
+ size_t z;
+
+ u = dev->si_drv1;
+ error = 0;
+
+ mtx_lock(&u->mutex);
+ while (u->buf_wp == u->buf_rp) {
+ error = msleep(u->buf, &u->mutex, PZERO | PCATCH,
+ "gpibrd", hz);
+ if (error && error != EWOULDBLOCK) {
+ mtx_unlock(&u->mutex);
+ return (error);
+ }
+ }
+ while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) {
+ if (u->buf_wp < u->buf_rp)
+ z = u->bufsize - u->buf_rp;
+ else
+ z = u->buf_wp - u->buf_rp;
+ if (z > uio->uio_resid)
+ z = uio->uio_resid;
+ mtx_unlock(&u->mutex);
+ error = uiomove(u->buf + u->buf_rp, z, uio);
+ mtx_lock(&u->mutex);
+ if (error)
+ break;
+ u->buf_rp += z;
+ u->buf_rp &= (u->bufsize - 1);
+ }
+ if (u->wreg[IMR1] == 0)
+ upd7210_wr(u, IMR1, 0x01);
+ mtx_unlock(&u->mutex);
+ return (error);
+}
+
+static struct cdevsw gpib_l_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "gpib_l",
+ .d_open = gpib_l_open,
+ .d_close = gpib_l_close,
+ .d_read = gpib_l_read,
+};
+
+/* Housekeeping */
+
+void
+upd7210attach(struct upd7210 *u)
+{
+ int unit = 0;
+ struct cdev *dev;
+
+ mtx_init(&u->mutex, "gpib", NULL, MTX_DEF);
+ u->cdev = make_dev(&gpib_l_cdevsw, unit,
+ UID_ROOT, GID_WHEEL, 0444,
+ "gpib%ul", unit);
+ u->cdev->si_drv1 = u;
+
+ dev = make_dev(&gpib_ib_cdevsw, unit,
+ UID_ROOT, GID_WHEEL, 0444,
+ "gpib%uib", unit);
+ dev->si_drv1 = u;
+ dev_depends(u->cdev, dev);
+}
diff --git a/sys/dev/ieee488/upd7210.h b/sys/dev/ieee488/upd7210.h
new file mode 100644
index 000000000000..7ba0f8eb8d10
--- /dev/null
+++ b/sys/dev/ieee488/upd7210.h
@@ -0,0 +1,234 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Locating an actual µPD7210 data book has proven quite impossible for me.
+ * There are a fair number of newer chips which are supersets of the µPD7210
+ * but they are particular eager to comprehensively mark what the extensions
+ * are and what is in the base set. Some even give the registers and their
+ * bits new names.
+ *
+ * The following information is based on a description of the µPD7210 found
+ * in an old manual for a VME board which used the chip.
+ */
+
+#ifndef _DEV_IEEE488_UPD7210_H_
+#define _DEV_IEEE488_UPD7210_H_
+#ifdef _KERNEL
+
+struct upd7210;
+struct ibfoo;
+
+/* upd7210 interface definitions for HW drivers */
+
+typedef int upd7210_irq_t(struct upd7210 *, int);
+
+struct upd7210 {
+ bus_space_handle_t reg_handle[8];
+ bus_space_tag_t reg_tag[8];
+ u_int reg_offset[8];
+ int dmachan;
+
+ /* private stuff */
+ struct mtx mutex;
+ uint8_t rreg[8];
+ uint8_t wreg[8 + 8];
+
+ upd7210_irq_t *irq;
+
+ int busy;
+ u_char *buf;
+ size_t bufsize;
+ u_int buf_wp;
+ u_int buf_rp;
+ struct cdev *cdev;
+
+ struct ibfoo *ibfoo;
+};
+
+#ifdef UPD7210_HW_DRIVER
+void upd7210intr(void *);
+void upd7210attach(struct upd7210 *);
+#endif
+
+#ifdef UPD7210_SW_DRIVER
+
+/* upd7210 hardware definitions. */
+
+/* Write registers */
+enum upd7210_wreg {
+ CDOR = 0, /* Command/Data Out Register */
+ IMR1 = 1, /* Interrupt Mask Register 1 */
+ IMR2 = 2, /* Interrupt Mask Register 2 */
+ SPMR = 3, /* Serial Poll Mode Register */
+ ADMR = 4, /* ADdress Mode Register */
+ AUXMR = 5, /* AUXilliary Mode Register */
+ ICR = 5, /* Internal Counter Register */
+ PPR = 5, /* Parallel Poll Register */
+ AUXRA = 5, /* AUXilliary Register A */
+ AUXRB = 5, /* AUXilliary Register B */
+ AUXRE = 5, /* AUXilliary Register E */
+ ADR = 6, /* ADdress Register */
+ EOSR = 7, /* End-Of-String Register */
+};
+
+/* Read registers */
+enum upd7210_rreg {
+ DIR = 0, /* Data In Register */
+ ISR1 = 1, /* Interrupt Status Register 1 */
+ ISR2 = 2, /* Interrupt Status Register 2 */
+ SPSR = 3, /* Serial Poll Status Register */
+ ADSR = 4, /* ADdress Status Register */
+ CPTR = 5, /* Command Pass Though Register */
+ ADR0 = 6, /* ADdress Register 0 */
+ ADR1 = 7, /* ADdress Register 1 */
+};
+
+/* Bits for ISR1 and IMR1 */
+#define IXR1_DI (1 << 0) /* Data In */
+#define IXR1_DO (1 << 1) /* Data Out */
+#define IXR1_ERR (1 << 2) /* Error */
+#define IXR1_DEC (1 << 3) /* Device Clear */
+#define IXR1_ENDRX (1 << 4) /* End Received */
+#define IXR1_DET (1 << 5) /* Device Execute Trigger */
+#define IXR1_APT (1 << 6) /* Address Pass-Through */
+#define IXR1_CPT (1 << 7) /* Command Pass-Through */
+
+/* Bits for ISR2 and IMR2 */
+#define IXR2_ADSC (1 << 0) /* Addressed Status Change */
+#define IXR2_REMC (1 << 1) /* Remote Change */
+#define IXR2_LOKC (1 << 2) /* Lockout Change */
+#define IXR2_CO (1 << 3) /* Command Out */
+#define ISR2_REM (1 << 4) /* Remove */
+#define IMR2_DMAI (1 << 4) /* DMA In Enable */
+#define ISR2_LOK (1 << 5) /* Lockout */
+#define IMR2_DMAO (1 << 5) /* DMA Out Enable */
+#define IXR2_SRQI (1 << 6) /* Service Request Input */
+#define ISR2_INT (1 << 7) /* Interrupt */
+
+#define SPSR_PEND (1 << 6) /* Pending */
+#define SPMR_RSV (1 << 6) /* Request SerVice */
+
+#define ADSR_MJMN (1 << 0) /* MaJor MiNor */
+#define ADSR_TA (1 << 1) /* Talker Active */
+#define ADSR_LA (1 << 2) /* Listener Active */
+#define ADSR_TPAS (1 << 3) /* Talker Primary Addr. State */
+#define ADSR_LPAS (1 << 4) /* Listener Primary Addr. State */
+#define ADSR_SPMS (1 << 5) /* Serial Poll Mode State */
+#define ADSR_ATN (1 << 6) /* Attention */
+#define ADSR_CIC (1 << 7) /* Controller In Charge */
+
+#define ADMR_ADM0 (1 << 0) /* Address Mode 0 */
+#define ADMR_ADM1 (1 << 1) /* Address Mode 1 */
+#define ADMR_TRM0 (1 << 4) /* Transmit/Receive Mode 0 */
+#define ADMR_TRM1 (1 << 5) /* Transmit/Receive Mode 1 */
+#define ADMR_LON (1 << 6) /* Listen Only */
+#define ADMR_TON (1 << 7) /* Talk Only */
+
+/* Constant part of overloaded write registers */
+#define C_ICR 0x20
+#define C_PPR 0x60
+#define C_AUXA 0x80
+#define C_AUXB 0xa0
+#define C_AUXE 0xc0
+
+#define AUXMR_PON 0x00 /* Immediate Execute pon */
+#define AUXMR_CPP 0x01 /* Clear Parallel Poll */
+#define AUXMR_CRST 0x02 /* Chip Reset */
+#define AUXMR_RFD 0x03 /* Finish Handshake */
+#define AUXMR_TRIG 0x04 /* Trigger */
+#define AUXMR_RTL 0x05 /* Return to local */
+#define AUXMR_SEOI 0x06 /* Send EOI */
+#define AUXMR_NVSA 0x07 /* Non-Valid Secondary cmd/addr */
+ /* 0x08 undefined/unknown */
+#define AUXMR_SPP 0x09 /* Set Parallel Poll */
+ /* 0x0a undefined/unknown */
+ /* 0x0b undefined/unknown */
+ /* 0x0c undefined/unknown */
+ /* 0x0d undefined/unknown */
+ /* 0x0e undefined/unknown */
+#define AUXMR_VSA 0x0f /* Valid Secondary cmd/addr */
+#define AUXMR_GTS 0x10 /* Go to Standby */
+#define AUXMR_TCA 0x11 /* Take Control Async (pulsed) */
+#define AUXMR_TCS 0x12 /* Take Control Synchronously */
+#define AUXMR_LISTEN 0x13 /* Listen */
+#define AUXMR_DSC 0x14 /* Disable System Control */
+ /* 0x15 undefined/unknown */
+#define AUXMR_SIFC 0x16 /* Set IFC */
+#define AUXMR_CREN 0x17 /* Clear REN */
+ /* 0x18 undefined/unknown */
+ /* 0x19 undefined/unknown */
+#define AUXMR_TCSE 0x1a /* Take Control Sync on End */
+#define AUXMR_LCM 0x1b /* Listen Continuously Mode */
+#define AUXMR_LUNL 0x1c /* Local Unlisten */
+#define AUXMR_EPP 0x1d /* Execute Parallel Poll */
+#define AUXMR_CIFC 0x1e /* Clear IFC */
+#define AUXMR_SREN 0x1f /* Set REN */
+
+#define PPR_U (1 << 4) /* Unconfigure */
+#define PPR_S (1 << 3) /* Status Polarity */
+
+#define AUXA_HLDA (1 << 0) /* Holdoff on All */
+#define AUXA_HLDE (1 << 1) /* Holdoff on END */
+#define AUXA_REOS (1 << 2) /* End on EOS received */
+#define AUXA_XEOS (1 << 3) /* Transmit END with EOS */
+#define AUXA_BIN (1 << 4) /* Binary */
+
+#define AUXB_CPTE (1 << 0) /* Cmd Pass Through Enable */
+#define AUXB_SPEOI (1 << 1) /* Send Serial Poll EOI */
+#define AUXB_TRI (1 << 2) /* Three-State Timing */
+#define AUXB_INV (1 << 3) /* Invert */
+#define AUXB_ISS (1 << 4) /* Individual Status Select */
+
+#define AUXE_DHDT (1 << 0) /* DAC Holdoff on DTAS */
+#define AUXE_DHDC (1 << 1) /* DAC Holdoff on DCAS */
+
+#define ADR0_DL0 (1 << 5) /* Disable Listener 0 */
+#define ADR0_DT0 (1 << 6) /* Disable Talker 0 */
+
+#define ADR_DL (1 << 5) /* Disable Listener */
+#define ADR_DT (1 << 6) /* Disable Talker */
+#define ADR_ARS (1 << 7) /* Address Register Select */
+
+#define ADR1_DL1 (1 << 5) /* Disable Listener 1 */
+#define ADR1_DT1 (1 << 6) /* Disable Talker 1 */
+#define ADR1_EOI (1 << 7) /* End or Identify */
+
+/* Stuff from software drivers */
+extern struct cdevsw gpib_l_cdevsw;
+extern struct cdevsw gpib_ib_cdevsw;
+
+/* Stuff from upd7210.c */
+void upd7210_print_isr(u_int isr1, u_int isr2);
+u_int upd7210_rd(struct upd7210 *u, enum upd7210_rreg reg);
+void upd7210_wr(struct upd7210 *u, enum upd7210_wreg reg, u_int val);
+int upd7210_take_ctrl_async(struct upd7210 *u);
+int upd7210_goto_standby(struct upd7210 *u);
+
+#endif /* UPD7210_SW_DRIVER */
+
+#endif /* _KERNEL */
+#endif /* _DEV_IEEE488_UPD7210_H_ */