Index: stable/8/sys/amd64/include/xen =================================================================== --- stable/8/sys/amd64/include/xen (revision 204490) +++ stable/8/sys/amd64/include/xen (revision 204491) Property changes on: stable/8/sys/amd64/include/xen ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/amd64/include/xen:r203360 Index: stable/8/sys/cddl/contrib/opensolaris =================================================================== --- stable/8/sys/cddl/contrib/opensolaris (revision 204490) +++ stable/8/sys/cddl/contrib/opensolaris (revision 204491) Property changes on: stable/8/sys/cddl/contrib/opensolaris ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/cddl/contrib/opensolaris:r203360 Index: stable/8/sys/contrib/dev/acpica =================================================================== --- stable/8/sys/contrib/dev/acpica (revision 204490) +++ stable/8/sys/contrib/dev/acpica (revision 204491) Property changes on: stable/8/sys/contrib/dev/acpica ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/contrib/dev/acpica:r203360 Index: stable/8/sys/contrib/pf =================================================================== --- stable/8/sys/contrib/pf (revision 204490) +++ stable/8/sys/contrib/pf (revision 204491) Property changes on: stable/8/sys/contrib/pf ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/contrib/pf:r203360 Index: stable/8/sys/dev/ieee488/ibfoo.c =================================================================== --- stable/8/sys/dev/ieee488/ibfoo.c (revision 204490) +++ stable/8/sys/dev/ieee488/ibfoo.c (revision 204491) @@ -1,1005 +1,1127 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 2010 Joerg Wunsch * 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 __FBSDID("$FreeBSD$"); # define IBDEBUG # undef IBDEBUG #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #define UPD7210_SW_DRIVER #include +#include static MALLOC_DEFINE(M_IBFOO, "IBFOO", "IBFOO"); /* ibfoo API */ #include /* 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 + DMA_IDATA, + FIFO_IDATA, + FIFO_ODATA, + FIFO_CMD } 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) +gpib_ib_irq(struct upd7210 *u, int isr_3) { 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; + case FIFO_IDATA: + if (!(isr_3 & 0x15)) + return (0); + while (ib->buflen != 0 && (isr_3 & 0x04 /* NEF */) != 0) { + *ib->buf = bus_read_1(u->reg_res[0], fifob); + ib->buf++; + ib->buflen--; + isr_3 = bus_read_1(u->reg_res[0], isr3); + } + if ((isr_3 & 0x01) != 0 /* xfr done */ || + (u->rreg[ISR1] & IXR1_ENDRX) != 0 || + ib->buflen == 0) + break; + if (isr_3 & 0x10) + /* xfr stopped */ + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + upd7210_wr(u, AUXMR, AUXMR_RFD); + return (1); + case FIFO_CMD: + case FIFO_ODATA: + if (!(isr_3 & 0x19)) + return (0); + if (ib->buflen == 0) + /* xfr DONE */ + break; + while (ib->buflen != 0 && (isr_3 & 0x08 /* NFF */) != 0) { + bus_write_1(u->reg_res[0], fifob, *ib->buf); + ib->buf++; + ib->buflen--; + isr_3 = bus_read_1(u->reg_res[0], isr3); + } + if (isr_3 & 0x10) + /* xfr stopped */ + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + if (ib->buflen == 0) + /* no more NFF interrupts wanted */ + bus_write_1(u->reg_res[0], imr3, 0x11); /* STOP IE, DONE IE */ + return (1); default: return (0); } upd7210_wr(u, IMR1, 0); upd7210_wr(u, IMR2, 0); + if (u->use_fifo) { + bus_write_1(u->reg_res[0], imr3, 0x00); + bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft RESET */ + } 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_int isr_3; 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 (u->use_fifo) + isr_3 = bus_read_1(u->reg_res[0], isr3); + else + isr_3 = 0; + gpib_ib_irq(u, isr_3); } 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); + if (u->use_fifo) { + bus_write_1(u->reg_res[0], imr3, 0x00); + bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft RESET */ + } 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); + if (u->use_fifo) + bus_write_1(u->reg_res[0], imr3, 0x00); } 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); + if (u->use_fifo) { + /* TNT5004 or TNT4882 in FIFO mode */ + ib->mode = FIFO_CMD; + upd7210_wr(u, AUXMR, 0x51); /* holdoff immediately */ + bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */ + bus_write_1(u->reg_res[0], cfg, 0x80); /* CMD, xfer OUT, 8-bit FIFO */ + bus_write_1(u->reg_res[0], imr3, 0x19); /* STOP IE, NFF IE, DONE IE */ + bus_write_1(u->reg_res[0], cnt0, -len); + bus_write_1(u->reg_res[0], cnt1, (-len) >> 8); + bus_write_1(u->reg_res[0], cnt2, (-len) >> 16); + bus_write_1(u->reg_res[0], cnt3, (-len) >> 24); + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + } else { + ib->mode = PIO_CMD; + upd7210_wr(u, IMR2, IXR2_CO); + gpib_ib_irq(u, 0); + } - gpib_ib_irq(u, 1); - gpib_ib_wait_xfer(u, ib); + if (u->use_fifo) + bus_write_1(u->reg_res[0], cmdr, 0x08); /* STOP */ + 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); + if (u->use_fifo) { + /* TNT5004 or TNT4882 in FIFO mode */ + ib->mode = FIFO_ODATA; + bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */ + if (ib->doeoi) + bus_write_1(u->reg_res[0], cfg, 0x08); /* CCEN */ + else + bus_write_1(u->reg_res[0], cfg, 0x00); /* xfer OUT, 8-bit FIFO */ + bus_write_1(u->reg_res[0], imr3, 0x19); /* STOP IE, NFF IE, DONE IE */ + bus_write_1(u->reg_res[0], cnt0, -len); + bus_write_1(u->reg_res[0], cnt1, (-len) >> 8); + bus_write_1(u->reg_res[0], cnt2, (-len) >> 16); + bus_write_1(u->reg_res[0], cnt3, (-len) >> 24); + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + } else { + ib->mode = PIO_ODATA; + upd7210_wr(u, IMR1, IXR1_DO); + } gpib_ib_wait_xfer(u, ib); + if (u->use_fifo) + bus_write_1(u->reg_res[0], cmdr, 0x08); /* STOP */ + 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); + if (u->use_fifo) { + /* TNT5004 or TNT4882 in FIFO mode */ + ib->mode = FIFO_IDATA; + bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */ + bus_write_1(u->reg_res[0], cfg, 0x20); /* xfer IN, 8-bit FIFO */ + bus_write_1(u->reg_res[0], cnt0, -len); + bus_write_1(u->reg_res[0], cnt1, (-len) >> 8); + bus_write_1(u->reg_res[0], cnt2, (-len) >> 16); + bus_write_1(u->reg_res[0], cnt3, (-len) >> 24); + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + upd7210_wr(u, AUXMR, AUXMR_RFD); + bus_write_1(u->reg_res[0], imr3, 0x15); /* STOP IE, NEF IE, DONE IE */ + } else { + ib->mode = PIO_IDATA; + upd7210_wr(u, IMR1, IXR1_DI); + } gpib_ib_wait_xfer(u, ib); + if (u->use_fifo) + bus_write_1(u->reg_res[0], cmdr, 0x08); /* STOP */ + 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, CALLOUT_MPSAFE); 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); + if (u->use_fifo) { + bus_write_1(u->reg_res[0], imr3, 0x00); + bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft reset */ + bus_write_1(u->reg_res[0], cmdr, 0x03); /* set system + * controller bit */ + } 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); + if (u->use_fifo) { + bus_write_1(u->reg_res[0], imr3, 0x00); + bus_write_1(u->reg_res[0], cmdr, 0x02); /* clear system + * controller bit */ + } 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, }; Index: stable/8/sys/dev/ieee488/pcii.c =================================================================== --- stable/8/sys/dev/ieee488/pcii.c (revision 204490) +++ stable/8/sys/dev/ieee488/pcii.c (revision 204491) @@ -1,252 +1,255 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp * Copyright (c) 2010 Joerg Wunsch * 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" * "National Instruments GPIB-PCII/PCIIA" (in PCIIa mode) * "Axiom AX5488" * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define UPD7210_HW_DRIVER #include struct pcii_softc { int foo; struct resource *res[11]; 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 struct resource_spec pcii_res_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, { SYS_RES_DRQ, 0, RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL}, { SYS_RES_IOPORT, 0, RF_ACTIVE}, { SYS_RES_IOPORT, 1, RF_ACTIVE}, { SYS_RES_IOPORT, 2, RF_ACTIVE}, { SYS_RES_IOPORT, 3, RF_ACTIVE}, { SYS_RES_IOPORT, 4, RF_ACTIVE}, { SYS_RES_IOPORT, 5, RF_ACTIVE}, { SYS_RES_IOPORT, 6, RF_ACTIVE}, { SYS_RES_IOPORT, 7, RF_ACTIVE}, { SYS_RES_IOPORT, 8, RF_ACTIVE | RF_SHAREABLE}, { -1, 0, 0 } }; static driver_t pcii_driver = { "pcii", pcii_methods, sizeof(struct pcii_softc), }; static int pcii_probe(device_t dev) { int rid, i, j; u_long start, count, addr; int error = 0; struct pcii_softc *sc; device_set_desc(dev, "PCII IEEE-4888 controller"); sc = device_get_softc(dev); rid = 0; if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) return ENXIO; /* * The PCIIA decodes a fixed pattern of 0x2e1 for the lower 10 * address bits A0 ... A9. Bits A10 through A12 are used by * the µPD7210 register select lines. This makes the * individual 7210 register being 0x400 bytes apart in the ISA * bus address space. Address bits A13 and A14 are compared * to a DIP switch setting on the card, allowing for up to 4 * different cards being installed (at base addresses 0x2e1, * 0x22e1, 0x42e1, and 0x62e1, respectively). A15 has been * used to select an optional on-board time-of-day clock chip * (MM58167A) on the original PCIIA rather than the µPD7210 * (which is not implemented on later boards). The * documentation states the respective addresses for that chip * should be handled as reserved addresses, which we don't do * (right now). Finally, the IO addresses 0x2f0 ... 0x2f7 for * a "special interrupt handling feature" (re-enable * interrupts so the IRQ can be shared). * * Usually, the user will only set the base address in the * device hints, so we handle the rest here. * * (Source: GPIB-PCIIA Technical Reference Manual, September * 1989 Edition, National Instruments.) */ if ((start & 0x3ff) != 0x2e1) { if (bootverbose) printf("pcii_probe: PCIIA base address 0x%lx not " "0x2e1/0x22e1/0x42e1/0x62e1\n", start); return (ENXIO); } for (rid = 0, addr = start; rid < 8; rid++, addr += 0x400) { if (bus_set_resource(dev, SYS_RES_IOPORT, rid, addr, 1) != 0) { printf("pcii_probe: could not set IO port 0x%lx\n", addr); return (ENXIO); } } if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) { printf("pcii_probe: cannot obtain IRQ level\n"); return ENXIO; } if (start > 7) { printf("pcii_probe: IRQ level %lu too high\n", start); return ENXIO; } if (bus_set_resource(dev, SYS_RES_IOPORT, 8, 0x2f0 + start, 1) != 0) { printf("pcii_probe: could not set IO port 0x%3lx\n", 0x2f0 + start); return (ENXIO); } error = bus_alloc_resources(dev, pcii_res_spec, sc->res); if (error) { printf("pcii_probe: Could not allocate resources\n"); return (error); } error = ENXIO; /* * Perform some basic tests on the µPD7210 registers. At * least *some* register must read different from 0x00 or * 0xff. */ for (i = 0; i < 8; i++) { j = bus_read_1(sc->res[2 + i], 0); if (j != 0x00 && j != 0xff) error = 0; } /* SPSR/SPMR read/write test */ if (!error) { bus_write_1(sc->res[2 + 3], 0, 0x55); if (bus_read_1(sc->res[2 + 3], 0) != 0x55) error = ENXIO; } if (!error) { bus_write_1(sc->res[2 + 3], 0, 0xaa); if (bus_read_1(sc->res[2 + 3], 0) != 0xaa) error = ENXIO; } if (error) printf("pcii_probe: probe failure\n"); bus_release_resources(dev, pcii_res_spec, sc->res); return (error); } static int pcii_attach(device_t dev) { struct pcii_softc *sc; u_long start, count; int unit; int rid; int 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"); if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) { printf("pcii_attach: cannot obtain IRQ number\n"); return ENXIO; } error = bus_alloc_resources(dev, pcii_res_spec, sc->res); if (error) return (error); error = bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE, NULL, upd7210intr, &sc->upd7210, &sc->intr_handler); if (error) { bus_release_resources(dev, pcii_res_spec, sc->res); return (error); } for (rid = 0; rid < 8; rid++) { sc->upd7210.reg_res[rid] = sc->res[2 + rid]; sc->upd7210.reg_offset[rid] = 0; } sc->upd7210.irq_clear_res = sc->res[10]; + sc->upd7210.use_fifo = 0; if (sc->res[1] == NULL) sc->upd7210.dmachan = -1; else sc->upd7210.dmachan = rman_get_start(sc->res[1]); upd7210attach(&sc->upd7210); - return (error); + device_printf(dev, "attached gpib%d\n", sc->upd7210.unit); + + return (0); } DRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0); DRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0); Index: stable/8/sys/dev/ieee488/tnt4882.c =================================================================== --- stable/8/sys/dev/ieee488/tnt4882.c (revision 204490) +++ stable/8/sys/dev/ieee488/tnt4882.c (revision 204491) @@ -1,349 +1,320 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 2010 Joerg Wunsch * 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$ */ #include #include #include #include #include #include #include #include #include #include #include /* vtophys */ #include #include #include #define UPD7210_HW_DRIVER 1 #include +#include struct tnt_softc { int foo; struct upd7210 upd7210; struct resource *res[3]; void *intr_handler; }; static struct resource_spec tnt_res_spec[] = { { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE}, { SYS_RES_MEMORY, PCIR_BAR(1), RF_ACTIVE}, { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, { -1, 0 } }; -enum tnt4882reg { - dir = 0x00, - cdor = 0x00, - isr1 = 0x02, - imr1 = 0x02, - isr2 = 0x04, - imr2 = 0x04, - accwr = 0x05, - spsr = 0x06, - spmr = 0x06, - intr = 0x07, - adsr = 0x08, - admr = 0x08, - cnt2 = 0x09, - cptr = 0x0a, - auxmr = 0x0a, - tauxcr = 0x0a, /* 9914 mode register */ - cnt3 = 0x0b, - adr0 = 0x0c, - adr = 0x0c, - hssel = 0x0d, - adr1 = 0x0e, - eosr = 0x0e, - sts1 = 0x10, - cfg = 0x10, - dsr = 0x11, - sh_cnt = 0x11, - imr3 = 0x12, - hier = 0x13, - cnt0 = 0x14, - misc = 0x15, - cnt1 = 0x16, - csr = 0x17, - keyreg = 0x17, - fifob = 0x18, - fifoa = 0x19, - isr3 = 0x1a, - ccr = 0x1a, - sasr = 0x1b, - dcr = 0x1b, - sts2 = 0x1c, - cmdr = 0x1c, - isr0 = 0x1d, - imr0 = 0x1d, - timer = 0x1e, - bsr = 0x1f, - bcr = 0x1f -}; - struct tst { enum {RD, WT, xDELAY, END} action; enum tnt4882reg reg; uint8_t val; }; /* * From NI Application note 095: * Writing Functional Self-Tests for the TNT4882 GPIB Interface Chip * XXX: fill in the rest ? */ static struct tst tst_reset[] = { {WT, tauxcr, 0x80}, /* chip reset if in 9914 mode */ {WT, auxmr, 0x80}, /* swrst if swapped */ {WT, tauxcr, 0x99}, /* switch to 7210 mode */ {WT, auxmr, 0x99}, /* switch to 7210 mode if swapped */ {WT, auxmr, 0x02}, /* execute chip reset */ {WT, keyreg, 0x00}, /* important! clear the swap bit */ {WT, eosr, 0x00}, /* clear EOS register */ {WT, cdor, 0x00}, /* clear data lines */ {WT, imr1, 0x00}, /* disable all interrupts */ {WT, imr2, 0x00}, {WT, imr0, 0x80}, {WT, adr, 0x80}, {WT, adr, 0x00}, {WT, admr, 0x00}, /* clear addressing modes */ {WT, auxmr, 0x00}, /* release from idle state with pon */ {WT, auxmr, 0x60}, /* reset ppr */ {WT, bcr, 0x00}, /* reset bcr */ {WT, misc, 0x04}, /* set wrap plug bit */ {WT, cmdr, 0xB2}, /* issue soft reset */ {WT, hssel, 0x00}, /* select two-chip mode */ {END, 0, 0} }; static struct tst tst_read_reg[] = { {RD, isr1, 0x00}, /* Verify mask registers are clear */ {RD, isr2, 0x00}, {RD, adsr, 0x40}, /* Verify ATN is not asserted */ {RD, adr0, 0x00}, /* Verify Primary address not set */ {RD, adr1, 0x00}, /* Verify Secondary address not set */ {RD, sts1, 0x8B}, /* Verify DONE, STOP, HALT, and GSYNC set */ {RD, isr3, 0x19}, /* Verify STOP, Not Full FIFO, & DONE set */ {RD, sts2, 0x9A}, /* Verify FIFO A/B is empty */ {RD, sasr, 0x00}, /* Verify clear */ {RD, isr0, 0x01}, /* Verify SYNC bit is set */ {END, 0, 0} }; static struct tst tst_bsr_dcr[] = { {WT, bcr, 0x55}, /* Set DAV, NRFD, SRQ, and REN */ {WT, dcr, 0xAA}, /* Write pattern to GPIB data lines */ {RD, bsr, 0x55}, /* Verify DAV, NRFD, SRQ, and REN are set */ {RD, dsr, 0xAA}, /* Verify data pattern written previously */ {WT, bcr, 0xAA}, /* Set ATN, NDAC, EOI, & IFC */ {WT, dcr, 0x55}, /* Write pattern to GPIB data lines */ {RD, bsr, 0xAA}, /* Verify ATN, NDAC, EOI, & IFC are set */ {RD, dsr, 0x55}, /* Verify data pattern written previously */ {WT, bcr, 0x00}, /* Clear control lines */ {WT, dcr, 0x00}, /* Clear data lines */ {RD, bsr, 0x00}, /* Verify control lines are clear */ {RD, dsr, 0x00}, /* Verify data lines are clear */ {END, 0, 0} }; static struct tst tst_adr0_1[] = { {WT, adr, 0x55}, /* Set Primary talk address */ {WT, adr, 0xAA}, /* Set Secondary listen address */ {RD, adr0, 0x55}, /* Read Primary address */ {RD, adr1, 0x2A}, /* Read Secondary address */ {WT, adr, 0x2A}, /* Set Primay listen address */ {WT, adr, 0xD5}, /* Set Secondary talk address */ {RD, adr0, 0x2A}, /* Read Primary address */ {RD, adr1, 0x55}, /* Read Secondary address */ {END, 0, 0} }; static struct tst tst_cdor_dir[] = { {WT, admr, 0xF0}, /* program AT-GPIB as talker only and * listener only */ {RD, isr1, 0x02}, /* check DO bit set */ {RD, adsr, 0x46}, /* check AT-GPIB is both talker active * and listener active */ {WT, cdor, 0xAA}, /* write out data byte */ {xDELAY, 0, 1}, /* One ISA I/O Cycle (500-ns) */ {RD, isr1, 0x03}, /* check DO and DI bits set */ {RD, dir, 0xAA}, /* verify data received */ {WT, cdor, 0x55}, /* write out data byte */ {xDELAY, 0, 1}, /* One ISA I/O Cycle (500-ns) */ {RD, dir, 0x55}, /* verify data received */ {END, 0, 0} }; static struct tst tst_spmr_spsr[] = { {WT, spsr, 0x00}, /* Write pattern to SPSR register */ {RD, spmr, 0x00}, /* Read back previously written pattern */ {WT, spsr, 0xBF}, /* Write pattern to SPSR register */ {RD, spmr, 0xBF}, /* Read back previously written pattern */ {END, 0, 0} }; static struct tst tst_count0_1[] = { {WT, cnt0, 0x55}, /* Verify every other bit can be set */ {WT, cnt1, 0xAA}, {RD, cnt0, 0x55}, /* Read back previously written pattern */ {RD, cnt1, 0xAA}, {WT, cnt0, 0xAA}, /* Verify every other bit can be set */ {WT, cnt1, 0x55}, {RD, cnt0, 0xAA}, /* Read back previously written pattern */ {RD, cnt1, 0x55}, {END, 0, 0} }; static int tst_exec(struct tnt_softc *sc, struct tst *tp, const char *name) { uint8_t u; int step; for (step = 0; tp->action != END; tp++, step++) { switch (tp->action) { case WT: bus_write_1(sc->res[1], tp->reg, tp->val); break; case RD: u = bus_read_1(sc->res[1], tp->reg); if (u != tp->val) { printf( "Test %s, step %d: reg(%02x) = %02x", name, step, tp->reg, u); printf( "should have been %02x\n", tp->val); return (1); } break; case xDELAY: DELAY(tp->val); break; default: printf("Unknown action in test %s, step %d: %d\n", name, step, tp->action); return (1); } } if (bootverbose) printf("Test %s passed\n", name); return (0); } static int tnt_probe(device_t dev) { if (pci_get_vendor(dev) == 0x1093 && pci_get_device(dev) == 0xc801) { device_set_desc(dev, "NI PCI-GPIB"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int tnt_attach(device_t dev) { struct tnt_softc *sc; int error, i; + uint8_t version; sc = device_get_softc(dev); error = bus_alloc_resources(dev, tnt_res_spec, sc->res); if (error) return (error); error = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE, NULL, upd7210intr, &sc->upd7210, &sc->intr_handler); - /* Necessary magic for MITE */ + /* IO Device Window Base Size Register (IODWBSR) */ bus_write_4(sc->res[0], 0xc0, rman_get_start(sc->res[1]) | 0x80); tst_exec(sc, tst_reset, "Reset"); tst_exec(sc, tst_read_reg, "Read registers"); tst_exec(sc, tst_bsr_dcr, "BSR & DCR"); tst_exec(sc, tst_adr0_1, "ADR0,1"); tst_exec(sc, tst_cdor_dir, "CDOR/DIR"); tst_exec(sc, tst_spmr_spsr, "CPMR/SPSR"); tst_exec(sc, tst_count0_1, "COUNT0:1"); tst_exec(sc, tst_reset, "Reset"); + version = bus_read_1(sc->res[1], csr); + version = (version >> 4) & 0x0f; + device_printf(dev, "Chip version 0x%02x (TNT%s)\n", + version, + version >= 4? "5004 or above": "4882"); + if (version >= 4) { + device_printf(dev, "Forcing FIFO mode\n"); + sc->upd7210.use_fifo = 1; + } else { + sc->upd7210.use_fifo = 0; + } + /* pass 7210 interrupts through */ bus_write_1(sc->res[1], imr3, 0x02); for (i = 0; i < 8; i++) { sc->upd7210.reg_res[i] = sc->res[1]; sc->upd7210.reg_offset[i] = i * 2; } /* No DMA help */ sc->upd7210.dmachan = -1; /* No "special interrupt handling" needed here. */ sc->upd7210.irq_clear_res = NULL; upd7210attach(&sc->upd7210); + device_printf(dev, "attached gpib%d\n", sc->upd7210.unit); + + if (sc->upd7210.use_fifo) + bus_write_1(sc->res[0], hssel, 0x01); /* one-chip mode */ + return (0); } static int tnt_detach(device_t dev) { struct tnt_softc *sc; sc = device_get_softc(dev); bus_teardown_intr(dev, sc->res[2], sc->intr_handler); upd7210detach(&sc->upd7210); bus_release_resources(dev, tnt_res_spec, sc->res); return (0); } static device_method_t tnt4882_methods[] = { DEVMETHOD(device_probe, tnt_probe), DEVMETHOD(device_attach, tnt_attach), DEVMETHOD(device_detach, tnt_detach), { 0, 0 } }; static driver_t pci_gpib_driver = { "tnt4882", tnt4882_methods, sizeof(struct tnt_softc) }; static devclass_t pci_gpib_devclass; DRIVER_MODULE(pci_gpib, pci, pci_gpib_driver, pci_gpib_devclass, 0, 0); Index: stable/8/sys/dev/ieee488/tnt4882.h =================================================================== --- stable/8/sys/dev/ieee488/tnt4882.h (nonexistent) +++ stable/8/sys/dev/ieee488/tnt4882.h (revision 204491) @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2010 Joerg Wunsch + * 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$ + */ + +enum tnt4882reg { + dir = 0x00, + cdor = 0x00, + isr1 = 0x02, + imr1 = 0x02, + isr2 = 0x04, + imr2 = 0x04, + accwr = 0x05, + spsr = 0x06, + spmr = 0x06, + intr = 0x07, + adsr = 0x08, + admr = 0x08, + cnt2 = 0x09, + cptr = 0x0a, + auxmr = 0x0a, + tauxcr = 0x0a, /* 9914 mode register */ + cnt3 = 0x0b, + adr0 = 0x0c, + adr = 0x0c, + hssel = 0x0d, + adr1 = 0x0e, + eosr = 0x0e, + sts1 = 0x10, + cfg = 0x10, + dsr = 0x11, + sh_cnt = 0x11, + imr3 = 0x12, + hier = 0x13, + cnt0 = 0x14, + misc = 0x15, + cnt1 = 0x16, + csr = 0x17, + keyreg = 0x17, + fifob = 0x18, + fifoa = 0x19, + isr3 = 0x1a, + ccr = 0x1a, + sasr = 0x1b, + dcr = 0x1b, + sts2 = 0x1c, + cmdr = 0x1c, + isr0 = 0x1d, + imr0 = 0x1d, + timer = 0x1e, + bsr = 0x1f, + bcr = 0x1f +}; + Property changes on: stable/8/sys/dev/ieee488/tnt4882.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/8/sys/dev/ieee488/upd7210.c =================================================================== --- stable/8/sys/dev/ieee488/upd7210.c (revision 204490) +++ stable/8/sys/dev/ieee488/upd7210.c (revision 204491) @@ -1,320 +1,369 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp * Copyright (c) 2010 Joerg Wunsch * 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 __FBSDID("$FreeBSD$"); # define GPIB_DEBUG # undef GPIB_DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define UPD7210_HW_DRIVER #define UPD7210_SW_DRIVER #include +#include 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_read_1(u->reg_res[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_write_1(u->reg_res[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; + u_int isr_1, isr_2, isr_3; struct upd7210 *u; u = arg; mtx_lock(&u->mutex); - isr1 = upd7210_rd(u, ISR1); - isr2 = upd7210_rd(u, ISR2); - if (isr1 != 0 || isr2 != 0) { - if (u->busy == 0 || u->irq == NULL || !u->irq(u, 1)) { + isr_1 = upd7210_rd(u, ISR1); + isr_2 = upd7210_rd(u, ISR2); + if (u->use_fifo) { + isr_3 = bus_read_1(u->reg_res[0], isr3); + } else { + isr_3 = 0; + } + if (isr_1 != 0 || isr_2 != 0 || isr_3 != 0) { + if (u->busy == 0 || u->irq == NULL || !u->irq(u, isr_3)) { #if 0 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"); #endif } /* * "special interrupt handling" * * In order to implement shared IRQs, the original * PCIIa uses IO locations 0x2f0 + (IRQ#) as an output * location. If an ISR for a particular card has * detected this card triggered the IRQ, it must reset * the card's IRQ by writing (anything) to that IO * location. * * Some clones apparently don't implement this * feature, but National Instrument cards do. */ if (u->irq_clear_res != NULL) bus_write_1(u->irq_clear_res, 0, 42); } 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) +gpib_l_irq(struct upd7210 *u, int isr_3) { int i; + int have_data = 0; - if (u->rreg[ISR1] & 1) { + if (u->use_fifo) { + /* TNT5004 or TNT4882 in FIFO mode */ + if (isr_3 & 0x04) { + /* FIFO not empty */ + i = bus_read_1(u->reg_res[0], fifob); + have_data = 1; + bus_write_1(u->reg_res[0], cnt0, -1); + bus_write_1(u->reg_res[0], cnt1, (-1) >> 8); + bus_write_1(u->reg_res[0], cnt2, (-1) >> 16); + bus_write_1(u->reg_res[0], cnt3, (-1) >> 24); + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + } + } else if (u->rreg[ISR1] & 1) { i = upd7210_rd(u, DIR); + have_data = 1; + } + + if (have_data) { 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); + if (i < 8) { + if (u->use_fifo) + bus_write_1(u->reg_res[0], imr3, 0x00); + else + 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); + upd7210_wr(u, AUXMR, AUXMR_CRST); /* chip reset */ DELAY(10000); - upd7210_wr(u, AUXMR, C_ICR | 8); + upd7210_wr(u, AUXMR, C_ICR | 8); /* 8 MHz clock */ 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); + upd7210_wr(u, ADR, 0x60); /* ADR0: disable listener and talker 0 */ + upd7210_wr(u, ADR, 0xe0); /* ADR1: disable listener and talker 1 */ + upd7210_wr(u, ADMR, 0x70); /* listen-only (lon) */ + upd7210_wr(u, AUXMR, AUXMR_PON); /* immediate execute power-on (pon) */ + if (u->use_fifo) { + /* TNT5004 or TNT4882 in FIFO mode */ + bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */ + bus_write_1(u->reg_res[0], cfg, 0x20); /* xfer IN, 8-bit FIFO */ + bus_write_1(u->reg_res[0], cnt0, -1); + bus_write_1(u->reg_res[0], cnt1, (-1) >> 8); + bus_write_1(u->reg_res[0], cnt2, (-1) >> 16); + bus_write_1(u->reg_res[0], cnt3, (-1) >> 24); + bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ + bus_write_1(u->reg_res[0], imr3, 0x04); /* NEF IE */ + } else { + /* µPD7210/NAT7210, or TNT4882 in non-FIFO mode */ + upd7210_wr(u, IMR1, 0x01); /* data in interrupt enable */ + } 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; + if (u->use_fifo) { + /* TNT5004 or TNT4882 in FIFO mode */ + bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft RESET */ + bus_write_1(u->reg_res[0], imr3, 0x00); + } 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); + if (u->use_fifo) { + bus_write_1(u->reg_res[0], imr3, 0x04); /* NFF IE */ + } else { + 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 */ static struct unrhdr *units; void upd7210attach(struct upd7210 *u) { struct cdev *dev; if (units == NULL) units = new_unrhdr(0, INT_MAX, NULL); u->unit = alloc_unr(units); mtx_init(&u->mutex, "gpib", NULL, MTX_DEF); u->cdev = make_dev(&gpib_l_cdevsw, u->unit, UID_ROOT, GID_WHEEL, 0444, "gpib%ul", u->unit); u->cdev->si_drv1 = u; dev = make_dev(&gpib_ib_cdevsw, u->unit, UID_ROOT, GID_WHEEL, 0444, "gpib%uib", u->unit); dev->si_drv1 = u; dev_depends(u->cdev, dev); } void upd7210detach(struct upd7210 *u) { destroy_dev(u->cdev); mtx_destroy(&u->mutex); free_unr(units, u->unit); } Index: stable/8/sys/dev/ieee488/upd7210.h =================================================================== --- stable/8/sys/dev/ieee488/upd7210.h (revision 204490) +++ stable/8/sys/dev/ieee488/upd7210.h (revision 204491) @@ -1,236 +1,237 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp * Copyright (c) 2010 Joerg Wunsch * 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 { struct resource *reg_res[8]; struct resource *irq_clear_res; u_int reg_offset[8]; int dmachan; int unit; + int use_fifo; /* 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 *); void upd7210detach(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_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_ */ Index: stable/8/sys/dev/xen/xenpci =================================================================== --- stable/8/sys/dev/xen/xenpci (revision 204490) +++ stable/8/sys/dev/xen/xenpci (revision 204491) Property changes on: stable/8/sys/dev/xen/xenpci ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/dev/xen/xenpci:r203360 Index: stable/8/sys/netinet =================================================================== --- stable/8/sys/netinet (revision 204490) +++ stable/8/sys/netinet (revision 204491) Property changes on: stable/8/sys/netinet ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/netinet:r203360 Index: stable/8/sys =================================================================== --- stable/8/sys (revision 204490) +++ stable/8/sys (revision 204491) Property changes on: stable/8/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r203360