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