1141398Sphk/*- 2141398Sphk * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org> 3202870Sjoerg * Copyright (c) 2010 Joerg Wunsch <joerg@FreeBSD.org> 4141398Sphk * All rights reserved. 5141398Sphk * 6141398Sphk * Redistribution and use in source and binary forms, with or without 7141398Sphk * modification, are permitted provided that the following conditions 8141398Sphk * are met: 9141398Sphk * 1. Redistributions of source code must retain the above copyright 10141398Sphk * notice, this list of conditions and the following disclaimer. 11141398Sphk * 2. Redistributions in binary form must reproduce the above copyright 12141398Sphk * notice, this list of conditions and the following disclaimer in the 13141398Sphk * documentation and/or other materials provided with the distribution. 14141398Sphk * 15141398Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16141398Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17141398Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18141398Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19141398Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20141398Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21141398Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22141398Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23141398Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24141398Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25141398Sphk * SUCH DAMAGE. 26141398Sphk * 27230134Suqs * High-level driver for ��PD7210 based GPIB cards. 28141398Sphk * 29141398Sphk */ 30141398Sphk 31141398Sphk#include <sys/cdefs.h> 32141398Sphk__FBSDID("$FreeBSD: releng/10.3/sys/dev/ieee488/upd7210.c 230134 2012-01-15 13:23:43Z uqs $"); 33141398Sphk 34141398Sphk# define GPIB_DEBUG 35141398Sphk# undef GPIB_DEBUG 36141398Sphk 37141398Sphk#include <sys/param.h> 38141398Sphk#include <sys/systm.h> 39141398Sphk#include <sys/conf.h> 40141398Sphk#include <sys/malloc.h> 41141398Sphk#include <sys/kernel.h> 42141398Sphk#include <sys/limits.h> 43141398Sphk#include <sys/module.h> 44150525Sphk#include <sys/rman.h> 45141398Sphk#include <sys/bus.h> 46141398Sphk#include <sys/lock.h> 47141398Sphk#include <sys/mutex.h> 48141398Sphk#include <sys/uio.h> 49141398Sphk#include <sys/time.h> 50141398Sphk#include <machine/bus.h> 51141398Sphk#include <machine/resource.h> 52141398Sphk#include <isa/isavar.h> 53141398Sphk 54141747Sphk#define UPD7210_HW_DRIVER 55141747Sphk#define UPD7210_SW_DRIVER 56141398Sphk#include <dev/ieee488/upd7210.h> 57203360Sjoerg#include <dev/ieee488/tnt4882.h> 58141398Sphk 59141621Sphkstatic MALLOC_DEFINE(M_GPIB, "GPIB", "GPIB"); 60141398Sphk 61141398Sphk/* upd7210 generic stuff */ 62141398Sphk 63141747Sphkvoid 64141747Sphkupd7210_print_isr(u_int isr1, u_int isr2) 65141398Sphk{ 66141398Sphk printf("isr1=0x%b isr2=0x%b", 67141398Sphk isr1, "\20\10CPT\7APT\6DET\5ENDRX\4DEC\3ERR\2DO\1DI", 68141398Sphk isr2, "\20\10INT\7SRQI\6LOK\5REM\4CO\3LOKC\2REMC\1ADSC"); 69141398Sphk} 70141398Sphk 71141747Sphku_int 72141747Sphkupd7210_rd(struct upd7210 *u, enum upd7210_rreg reg) 73141398Sphk{ 74141398Sphk u_int r; 75141398Sphk 76202898Sjoerg r = bus_read_1(u->reg_res[reg], u->reg_offset[reg]); 77141398Sphk u->rreg[reg] = r; 78141398Sphk return (r); 79141398Sphk} 80141398Sphk 81141747Sphkvoid 82141747Sphkupd7210_wr(struct upd7210 *u, enum upd7210_wreg reg, u_int val) 83141398Sphk{ 84150153Sphk 85202898Sjoerg bus_write_1(u->reg_res[reg], u->reg_offset[reg], val); 86141398Sphk u->wreg[reg] = val; 87141398Sphk if (reg == AUXMR) 88141398Sphk u->wreg[8 + (val >> 5)] = val & 0x1f; 89141398Sphk} 90141398Sphk 91141398Sphkvoid 92141398Sphkupd7210intr(void *arg) 93141398Sphk{ 94203360Sjoerg u_int isr_1, isr_2, isr_3; 95141398Sphk struct upd7210 *u; 96141398Sphk 97141398Sphk u = arg; 98141398Sphk mtx_lock(&u->mutex); 99203360Sjoerg isr_1 = upd7210_rd(u, ISR1); 100203360Sjoerg isr_2 = upd7210_rd(u, ISR2); 101203360Sjoerg if (u->use_fifo) { 102203360Sjoerg isr_3 = bus_read_1(u->reg_res[0], isr3); 103203360Sjoerg } else { 104203360Sjoerg isr_3 = 0; 105203360Sjoerg } 106203360Sjoerg if (isr_1 != 0 || isr_2 != 0 || isr_3 != 0) { 107203360Sjoerg if (u->busy == 0 || u->irq == NULL || !u->irq(u, isr_3)) { 108156573Sphk#if 0 109202870Sjoerg printf("upd7210intr [%02x %02x %02x", 110202870Sjoerg upd7210_rd(u, DIR), isr1, isr2); 111202870Sjoerg printf(" %02x %02x %02x %02x %02x] ", 112202870Sjoerg upd7210_rd(u, SPSR), 113202870Sjoerg upd7210_rd(u, ADSR), 114202870Sjoerg upd7210_rd(u, CPTR), 115202870Sjoerg upd7210_rd(u, ADR0), 116141747Sphk upd7210_rd(u, ADR1)); 117202870Sjoerg upd7210_print_isr(isr1, isr2); 118202870Sjoerg printf("\n"); 119156573Sphk#endif 120202870Sjoerg } 121202870Sjoerg /* 122202870Sjoerg * "special interrupt handling" 123202870Sjoerg * 124202870Sjoerg * In order to implement shared IRQs, the original 125202870Sjoerg * PCIIa uses IO locations 0x2f0 + (IRQ#) as an output 126202870Sjoerg * location. If an ISR for a particular card has 127202870Sjoerg * detected this card triggered the IRQ, it must reset 128202870Sjoerg * the card's IRQ by writing (anything) to that IO 129202870Sjoerg * location. 130202870Sjoerg * 131202870Sjoerg * Some clones apparently don't implement this 132202870Sjoerg * feature, but National Instrument cards do. 133202870Sjoerg */ 134202898Sjoerg if (u->irq_clear_res != NULL) 135202898Sjoerg bus_write_1(u->irq_clear_res, 0, 42); 136141398Sphk } 137141398Sphk mtx_unlock(&u->mutex); 138141398Sphk} 139141398Sphk 140141747Sphkint 141141398Sphkupd7210_take_ctrl_async(struct upd7210 *u) 142141398Sphk{ 143141398Sphk int i; 144141398Sphk 145141747Sphk upd7210_wr(u, AUXMR, AUXMR_TCA); 146141398Sphk 147141747Sphk if (!(upd7210_rd(u, ADSR) & ADSR_ATN)) 148141398Sphk return (0); 149141398Sphk for (i = 0; i < 20; i++) { 150141398Sphk DELAY(1); 151141747Sphk if (!(upd7210_rd(u, ADSR) & ADSR_ATN)) 152141398Sphk return (0); 153141398Sphk } 154141398Sphk return (1); 155141398Sphk} 156141398Sphk 157141747Sphkint 158141398Sphkupd7210_goto_standby(struct upd7210 *u) 159141398Sphk{ 160141398Sphk int i; 161141398Sphk 162141747Sphk upd7210_wr(u, AUXMR, AUXMR_GTS); 163141398Sphk 164141747Sphk if (upd7210_rd(u, ADSR) & ADSR_ATN) 165141398Sphk return (0); 166141398Sphk for (i = 0; i < 20; i++) { 167141398Sphk DELAY(1); 168141747Sphk if (upd7210_rd(u, ADSR) & ADSR_ATN) 169141398Sphk return (0); 170141398Sphk } 171141398Sphk return (1); 172141398Sphk} 173141398Sphk 174141398Sphk/* Unaddressed Listen Only mode */ 175141398Sphk 176141398Sphkstatic int 177203360Sjoerggpib_l_irq(struct upd7210 *u, int isr_3) 178141398Sphk{ 179141398Sphk int i; 180203360Sjoerg int have_data = 0; 181141398Sphk 182203360Sjoerg if (u->use_fifo) { 183203360Sjoerg /* TNT5004 or TNT4882 in FIFO mode */ 184203360Sjoerg if (isr_3 & 0x04) { 185203360Sjoerg /* FIFO not empty */ 186203360Sjoerg i = bus_read_1(u->reg_res[0], fifob); 187203360Sjoerg have_data = 1; 188203360Sjoerg bus_write_1(u->reg_res[0], cnt0, -1); 189203360Sjoerg bus_write_1(u->reg_res[0], cnt1, (-1) >> 8); 190203360Sjoerg bus_write_1(u->reg_res[0], cnt2, (-1) >> 16); 191203360Sjoerg bus_write_1(u->reg_res[0], cnt3, (-1) >> 24); 192203360Sjoerg bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ 193203360Sjoerg } 194203360Sjoerg } else if (u->rreg[ISR1] & 1) { 195141747Sphk i = upd7210_rd(u, DIR); 196203360Sjoerg have_data = 1; 197203360Sjoerg } 198203360Sjoerg 199203360Sjoerg if (have_data) { 200141398Sphk u->buf[u->buf_wp++] = i; 201141398Sphk u->buf_wp &= (u->bufsize - 1); 202141398Sphk i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1); 203203360Sjoerg if (i < 8) { 204203360Sjoerg if (u->use_fifo) 205203360Sjoerg bus_write_1(u->reg_res[0], imr3, 0x00); 206203360Sjoerg else 207203360Sjoerg upd7210_wr(u, IMR1, 0); 208203360Sjoerg } 209141398Sphk wakeup(u->buf); 210141398Sphk return (1); 211141398Sphk } 212141398Sphk return (0); 213141398Sphk} 214141398Sphk 215141398Sphkstatic int 216141398Sphkgpib_l_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 217141398Sphk{ 218141398Sphk struct upd7210 *u; 219141398Sphk 220141398Sphk u = dev->si_drv1; 221141398Sphk 222141398Sphk mtx_lock(&u->mutex); 223144633Sphk if (u->busy) { 224144633Sphk mtx_unlock(&u->mutex); 225141398Sphk return (EBUSY); 226144633Sphk } 227141398Sphk u->busy = 1; 228141398Sphk u->irq = gpib_l_irq; 229141398Sphk mtx_unlock(&u->mutex); 230141398Sphk 231141398Sphk u->buf = malloc(PAGE_SIZE, M_GPIB, M_WAITOK); 232141398Sphk u->bufsize = PAGE_SIZE; 233141398Sphk u->buf_wp = 0; 234141398Sphk u->buf_rp = 0; 235141398Sphk 236203360Sjoerg upd7210_wr(u, AUXMR, AUXMR_CRST); /* chip reset */ 237141398Sphk DELAY(10000); 238203360Sjoerg upd7210_wr(u, AUXMR, C_ICR | 8); /* 8 MHz clock */ 239141398Sphk DELAY(1000); 240203360Sjoerg upd7210_wr(u, ADR, 0x60); /* ADR0: disable listener and talker 0 */ 241203360Sjoerg upd7210_wr(u, ADR, 0xe0); /* ADR1: disable listener and talker 1 */ 242203360Sjoerg upd7210_wr(u, ADMR, 0x70); /* listen-only (lon) */ 243203360Sjoerg upd7210_wr(u, AUXMR, AUXMR_PON); /* immediate execute power-on (pon) */ 244203360Sjoerg if (u->use_fifo) { 245203360Sjoerg /* TNT5004 or TNT4882 in FIFO mode */ 246203360Sjoerg bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */ 247203360Sjoerg bus_write_1(u->reg_res[0], cfg, 0x20); /* xfer IN, 8-bit FIFO */ 248203360Sjoerg bus_write_1(u->reg_res[0], cnt0, -1); 249203360Sjoerg bus_write_1(u->reg_res[0], cnt1, (-1) >> 8); 250203360Sjoerg bus_write_1(u->reg_res[0], cnt2, (-1) >> 16); 251203360Sjoerg bus_write_1(u->reg_res[0], cnt3, (-1) >> 24); 252203360Sjoerg bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */ 253203360Sjoerg bus_write_1(u->reg_res[0], imr3, 0x04); /* NEF IE */ 254203360Sjoerg } else { 255230134Suqs /* ��PD7210/NAT7210, or TNT4882 in non-FIFO mode */ 256203360Sjoerg upd7210_wr(u, IMR1, 0x01); /* data in interrupt enable */ 257203360Sjoerg } 258141398Sphk return (0); 259141398Sphk} 260141398Sphk 261141398Sphkstatic int 262141398Sphkgpib_l_close(struct cdev *dev, int oflags, int devtype, struct thread *td) 263141398Sphk{ 264141398Sphk struct upd7210 *u; 265141398Sphk 266141398Sphk u = dev->si_drv1; 267141398Sphk 268141398Sphk mtx_lock(&u->mutex); 269141398Sphk u->busy = 0; 270203360Sjoerg if (u->use_fifo) { 271203360Sjoerg /* TNT5004 or TNT4882 in FIFO mode */ 272203360Sjoerg bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft RESET */ 273203360Sjoerg bus_write_1(u->reg_res[0], imr3, 0x00); 274203360Sjoerg } 275141747Sphk upd7210_wr(u, AUXMR, AUXMR_CRST); 276141398Sphk DELAY(10000); 277141747Sphk upd7210_wr(u, IMR1, 0x00); 278141747Sphk upd7210_wr(u, IMR2, 0x00); 279141398Sphk free(u->buf, M_GPIB); 280141398Sphk u->buf = NULL; 281141398Sphk mtx_unlock(&u->mutex); 282141398Sphk return (0); 283141398Sphk} 284141398Sphk 285141398Sphkstatic int 286141398Sphkgpib_l_read(struct cdev *dev, struct uio *uio, int ioflag) 287141398Sphk{ 288141398Sphk struct upd7210 *u; 289141398Sphk int error; 290141398Sphk size_t z; 291141398Sphk 292141398Sphk u = dev->si_drv1; 293141398Sphk error = 0; 294141398Sphk 295141398Sphk mtx_lock(&u->mutex); 296141398Sphk while (u->buf_wp == u->buf_rp) { 297141398Sphk error = msleep(u->buf, &u->mutex, PZERO | PCATCH, 298141398Sphk "gpibrd", hz); 299141398Sphk if (error && error != EWOULDBLOCK) { 300141398Sphk mtx_unlock(&u->mutex); 301141398Sphk return (error); 302141398Sphk } 303141398Sphk } 304141398Sphk while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) { 305141398Sphk if (u->buf_wp < u->buf_rp) 306141398Sphk z = u->bufsize - u->buf_rp; 307141398Sphk else 308141398Sphk z = u->buf_wp - u->buf_rp; 309141398Sphk if (z > uio->uio_resid) 310141398Sphk z = uio->uio_resid; 311141398Sphk mtx_unlock(&u->mutex); 312141398Sphk error = uiomove(u->buf + u->buf_rp, z, uio); 313141398Sphk mtx_lock(&u->mutex); 314141398Sphk if (error) 315141398Sphk break; 316141398Sphk u->buf_rp += z; 317141398Sphk u->buf_rp &= (u->bufsize - 1); 318141398Sphk } 319203360Sjoerg if (u->use_fifo) { 320203360Sjoerg bus_write_1(u->reg_res[0], imr3, 0x04); /* NFF IE */ 321203360Sjoerg } else { 322203360Sjoerg if (u->wreg[IMR1] == 0) 323203360Sjoerg upd7210_wr(u, IMR1, 0x01); 324203360Sjoerg } 325141398Sphk mtx_unlock(&u->mutex); 326141398Sphk return (error); 327141398Sphk} 328141398Sphk 329141621Sphkstatic struct cdevsw gpib_l_cdevsw = { 330141398Sphk .d_version = D_VERSION, 331141398Sphk .d_name = "gpib_l", 332141398Sphk .d_open = gpib_l_open, 333141398Sphk .d_close = gpib_l_close, 334141398Sphk .d_read = gpib_l_read, 335141398Sphk}; 336141398Sphk 337141398Sphk/* Housekeeping */ 338141398Sphk 339150153Sphkstatic struct unrhdr *units; 340150153Sphk 341141398Sphkvoid 342141398Sphkupd7210attach(struct upd7210 *u) 343141398Sphk{ 344141398Sphk struct cdev *dev; 345141398Sphk 346150153Sphk if (units == NULL) 347179413Sed units = new_unrhdr(0, INT_MAX, NULL); 348150153Sphk u->unit = alloc_unr(units); 349141398Sphk mtx_init(&u->mutex, "gpib", NULL, MTX_DEF); 350150153Sphk u->cdev = make_dev(&gpib_l_cdevsw, u->unit, 351141398Sphk UID_ROOT, GID_WHEEL, 0444, 352150153Sphk "gpib%ul", u->unit); 353141398Sphk u->cdev->si_drv1 = u; 354141398Sphk 355150153Sphk dev = make_dev(&gpib_ib_cdevsw, u->unit, 356141398Sphk UID_ROOT, GID_WHEEL, 0444, 357150153Sphk "gpib%uib", u->unit); 358141398Sphk dev->si_drv1 = u; 359141398Sphk dev_depends(u->cdev, dev); 360141398Sphk} 361150153Sphk 362150153Sphkvoid 363150153Sphkupd7210detach(struct upd7210 *u) 364150153Sphk{ 365150153Sphk 366150153Sphk destroy_dev(u->cdev); 367150153Sphk mtx_destroy(&u->mutex); 368150153Sphk free_unr(units, u->unit); 369150153Sphk} 370