1/*-
2 * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
3 * Copyright (c) 2010 Joerg Wunsch <joerg@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * High-level driver for µPD7210 based GPIB cards.
28 *
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#  define	IBDEBUG
35#  undef	IBDEBUG
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/conf.h>
40#include <sys/malloc.h>
41#include <sys/kernel.h>
42#include <sys/limits.h>
43#include <sys/module.h>
44#include <sys/rman.h>
45#include <sys/bus.h>
46#include <sys/lock.h>
47#include <sys/mutex.h>
48#include <sys/uio.h>
49#include <sys/time.h>
50#include <machine/bus.h>
51#include <machine/resource.h>
52#include <isa/isavar.h>
53
54#include <dev/ieee488/ugpib.h>
55
56#define UPD7210_SW_DRIVER
57#include <dev/ieee488/upd7210.h>
58#include <dev/ieee488/tnt4882.h>
59
60static MALLOC_DEFINE(M_IBFOO, "IBFOO", "IBFOO");
61
62
63/* ibfoo API */
64
65#include <dev/ieee488/ibfoo_int.h>
66
67/* XXX: This is really a bitmap */
68enum h_kind {
69	H_DEV = 1,
70	H_BOARD = 2,
71	H_EITHER = 3
72};
73
74struct handle {
75	LIST_ENTRY(handle)	list;
76	int			handle;
77	enum h_kind		kind;
78	int			pad;
79	int			sad;
80	struct timeval		timeout;
81	int			eot;
82	int			eos;
83	int			dma;
84};
85
86struct ibfoo {
87	struct upd7210		*u;
88	LIST_HEAD(,handle)	handles;
89	struct unrhdr		*unrhdr;
90	struct callout		callout;
91	struct handle		*h;
92	struct ibarg		*ap;
93
94	enum {
95		IDLE,
96		BUSY,
97		PIO_IDATA,
98		PIO_ODATA,
99		PIO_CMD,
100		DMA_IDATA,
101		FIFO_IDATA,
102		FIFO_ODATA,
103		FIFO_CMD
104	}			mode;
105
106	struct timeval		deadline;
107
108	struct handle		*rdh;		/* addressed for read */
109	struct handle		*wrh;		/* addressed for write */
110
111	int		 	doeoi;
112
113	u_char			*buf;
114	u_int			buflen;
115};
116
117typedef int ibhandler_t(struct ibfoo *ib);
118
119static struct timeval timeouts[] = {
120	[TNONE] =	{    0,      0},
121	[T10us] =	{    0,     10},
122	[T30us] =	{    0,     30},
123	[T100us] =	{    0,    100},
124	[T300us] =	{    0,    300},
125	[T1ms] =	{    0,   1000},
126	[T3ms] =	{    0,   3000},
127	[T10ms] =	{    0,  10000},
128	[T30ms] =	{    0,  30000},
129	[T100ms] =	{    0, 100000},
130	[T300ms] =	{    0, 300000},
131	[T1s] =		{    1,      0},
132	[T3s] =		{    3,      0},
133	[T10s] =	{   10,      0},
134	[T30s] =	{   30,      0},
135	[T100s] =	{  100,      0},
136	[T300s] =	{  300,      0},
137	[T1000s] =	{ 1000,      0}
138};
139
140static const u_int max_timeouts = sizeof timeouts / sizeof timeouts[0];
141
142static int ibdebug;
143
144static int
145ib_set_error(struct ibarg *ap, int error)
146{
147
148	if (ap->__iberr == 0)
149		ap->__iberr = error;
150	ap->__ibsta |= ERR;
151	ap->__retval = ap->__ibsta;
152	return (0);
153}
154
155static int
156ib_had_timeout(struct ibarg *ap)
157{
158
159	ib_set_error(ap, EABO);
160	ap->__ibsta |= TIMO;
161	ap->__retval = ap->__ibsta;
162	return (0);
163}
164
165static int
166ib_set_errno(struct ibarg *ap, int errno)
167{
168
169	if (ap->__iberr == 0) {
170		ap->__iberr = EDVR;
171		ap->__ibcnt = errno;
172	}
173	ap->__ibsta |= ERR;
174	ap->__retval = ap->__ibsta;
175	return (0);
176}
177
178static int
179gpib_ib_irq(struct upd7210 *u, int isr_3)
180{
181	struct ibfoo *ib;
182
183	ib = u->ibfoo;
184
185	mtx_assert(&u->mutex, MA_OWNED);
186	switch (ib->mode) {
187	case PIO_CMD:
188		if (!(u->rreg[ISR2] & IXR2_CO))
189			return (0);
190		if (ib->buflen == 0)
191			break;
192		upd7210_wr(u, CDOR, *ib->buf);
193		ib->buf++;
194		ib->buflen--;
195		return (1);
196	case PIO_IDATA:
197		if (!(u->rreg[ISR1] & IXR1_DI))
198			return (0);
199		*ib->buf = upd7210_rd(u, DIR);
200		ib->buf++;
201		ib->buflen--;
202		if (ib->buflen == 0 || (u->rreg[ISR1] & IXR1_ENDRX))
203			break;
204		return (1);
205	case PIO_ODATA:
206		if (!(u->rreg[ISR1] & IXR1_DO))
207			return (0);
208		if (ib->buflen == 0)
209			break;
210		if (ib->buflen == 1 && ib->doeoi)
211			upd7210_wr(u, AUXMR, AUXMR_SEOI);
212		upd7210_wr(u, CDOR, *ib->buf);
213		ib->buf++;
214		ib->buflen--;
215		return (1);
216	case DMA_IDATA:
217		if (!(u->rreg[ISR1] & IXR1_ENDRX))
218			return (0);
219		break;
220	case FIFO_IDATA:
221		if (!(isr_3 & 0x15))
222			return (0);
223		while (ib->buflen != 0 && (isr_3 & 0x04 /* NEF */) != 0) {
224			*ib->buf = bus_read_1(u->reg_res[0], fifob);
225			ib->buf++;
226			ib->buflen--;
227			isr_3 = bus_read_1(u->reg_res[0], isr3);
228		}
229		if ((isr_3 & 0x01) != 0 /* xfr done */ ||
230		    (u->rreg[ISR1] & IXR1_ENDRX) != 0 ||
231		    ib->buflen == 0)
232			break;
233		if (isr_3 & 0x10)
234			/* xfr stopped */
235			bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */
236		upd7210_wr(u, AUXMR, AUXMR_RFD);
237		return (1);
238	case FIFO_CMD:
239	case FIFO_ODATA:
240		if (!(isr_3 & 0x19))
241			return (0);
242		if (ib->buflen == 0)
243			/* xfr DONE */
244			break;
245		while (ib->buflen != 0 && (isr_3 & 0x08 /* NFF */) != 0) {
246			bus_write_1(u->reg_res[0], fifob, *ib->buf);
247			ib->buf++;
248			ib->buflen--;
249			isr_3 = bus_read_1(u->reg_res[0], isr3);
250		}
251		if (isr_3 & 0x10)
252			/* xfr stopped */
253			bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */
254		if (ib->buflen == 0)
255			/* no more NFF interrupts wanted */
256			bus_write_1(u->reg_res[0], imr3, 0x11); /* STOP IE, DONE IE */
257		return (1);
258	default:
259		return (0);
260	}
261	upd7210_wr(u, IMR1, 0);
262	upd7210_wr(u, IMR2, 0);
263	if (u->use_fifo) {
264		bus_write_1(u->reg_res[0], imr3, 0x00);
265		bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft RESET */
266	}
267	ib->mode = BUSY;
268	wakeup(&ib->buflen);
269	return (1);
270}
271
272static void
273gpib_ib_timeout(void *arg)
274{
275	struct upd7210 *u;
276	struct ibfoo *ib;
277	struct timeval tv;
278	u_int isr_3;
279
280	u = arg;
281	ib = u->ibfoo;
282	mtx_lock(&u->mutex);
283	if (ib->mode == DMA_IDATA && isa_dmatc(u->dmachan)) {
284		KASSERT(u->dmachan >= 0, ("Bogus dmachan = %d", u->dmachan));
285		upd7210_wr(u, IMR1, 0);
286		upd7210_wr(u, IMR2, 0);
287		ib->mode = BUSY;
288		wakeup(&ib->buflen);
289	}
290	if (ib->mode > BUSY) {
291		upd7210_rd(u, ISR1);
292		upd7210_rd(u, ISR2);
293		if (u->use_fifo)
294			isr_3 = bus_read_1(u->reg_res[0], isr3);
295		else
296			isr_3 = 0;
297		gpib_ib_irq(u, isr_3);
298	}
299	if (ib->mode != IDLE && timevalisset(&ib->deadline)) {
300		getmicrouptime(&tv);
301		if (timevalcmp(&ib->deadline, &tv, <)) {
302			ib_had_timeout(ib->ap);
303			upd7210_wr(u, IMR1, 0);
304			upd7210_wr(u, IMR2, 0);
305			if (u->use_fifo) {
306				bus_write_1(u->reg_res[0], imr3, 0x00);
307				bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft RESET */
308			}
309			ib->mode = BUSY;
310			wakeup(&ib->buflen);
311		}
312	}
313	if (ib->mode != IDLE)
314		callout_reset(&ib->callout, hz / 5, gpib_ib_timeout, arg);
315	mtx_unlock(&u->mutex);
316}
317
318static void
319gpib_ib_wait_xfer(struct upd7210 *u, struct ibfoo *ib)
320{
321	int i;
322
323	mtx_assert(&u->mutex, MA_OWNED);
324	while (ib->mode > BUSY) {
325		i = msleep(&ib->buflen, &u->mutex,
326		    PZERO | PCATCH, "ibwxfr", 0);
327		if (i == EINTR) {
328			ib_set_errno(ib->ap, i);
329			break;
330		}
331		if (u->rreg[ISR1] & IXR1_ERR) {
332			ib_set_error(ib->ap, EABO);	/* XXX ? */
333			break;
334		}
335	}
336	if ((u->rreg[ISR1] & IXR1_ENDRX) != 0) {
337		ib->ap->__retval |= END;
338		ib->ap->__ibsta |= END;
339	}
340	if ((u->rreg[ISR2] & IXR2_SRQI) != 0) {
341		ib->ap->__retval |= SRQI;
342		ib->ap->__ibsta |= SRQI;
343	}
344	ib->mode = BUSY;
345	ib->buf = NULL;
346	upd7210_wr(u, IMR1, 0);
347	upd7210_wr(u, IMR2, 0);
348	if (u->use_fifo)
349		bus_write_1(u->reg_res[0], imr3, 0x00);
350}
351
352static void
353config_eos(struct upd7210 *u, struct handle *h)
354{
355	int i;
356
357	i = 0;
358	if (h->eos & REOS) {
359		upd7210_wr(u, EOSR, h->eos & 0xff);
360		i |= AUXA_REOS;
361	}
362	if (h->eos & XEOS) {
363		upd7210_wr(u, EOSR, h->eos & 0xff);
364		i |= AUXA_XEOS;
365	}
366	if (h->eos & BIN)
367		i |= AUXA_BIN;
368	upd7210_wr(u, AUXRA, C_AUXA | i);
369}
370
371/*
372 * Look up the handle, and set the deadline if the handle has a timeout.
373 */
374static int
375gethandle(struct upd7210 *u, struct ibarg *ap, struct handle **hp)
376{
377	struct ibfoo *ib;
378	struct handle *h;
379
380	KASSERT(ap->__field & __F_HANDLE, ("gethandle without __F_HANDLE"));
381	ib = u->ibfoo;
382	LIST_FOREACH(h, &ib->handles, list) {
383		if (h->handle == ap->handle) {
384			*hp = h;
385			return (0);
386		}
387	}
388	ib_set_error(ap, EARG);
389	return (1);
390}
391
392static int
393pio_cmd(struct upd7210 *u, u_char *cmd, int len)
394{
395	struct ibfoo *ib;
396
397	ib = u->ibfoo;
398
399	if (ib->rdh != NULL || ib->wrh != NULL) {
400		upd7210_take_ctrl_async(u);
401		ib->rdh = NULL;
402		ib->wrh = NULL;
403	}
404	mtx_lock(&u->mutex);
405	ib->buf = cmd;
406	ib->buflen = len;
407	if (u->use_fifo) {
408		/* TNT5004 or TNT4882 in FIFO mode */
409		ib->mode = FIFO_CMD;
410		upd7210_wr(u, AUXMR, 0x51);		/* holdoff immediately */
411		bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */
412		bus_write_1(u->reg_res[0], cfg, 0x80); /* CMD, xfer OUT, 8-bit FIFO */
413		bus_write_1(u->reg_res[0], imr3, 0x19); /* STOP IE, NFF IE, DONE IE */
414		bus_write_1(u->reg_res[0], cnt0, -len);
415		bus_write_1(u->reg_res[0], cnt1, (-len) >> 8);
416		bus_write_1(u->reg_res[0], cnt2, (-len) >> 16);
417		bus_write_1(u->reg_res[0], cnt3, (-len) >> 24);
418		bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */
419	} else {
420		ib->mode = PIO_CMD;
421		upd7210_wr(u, IMR2, IXR2_CO);
422		gpib_ib_irq(u, 0);
423	}
424
425	gpib_ib_wait_xfer(u, ib);
426
427	if (u->use_fifo)
428		bus_write_1(u->reg_res[0], cmdr, 0x08); /* STOP */
429
430	mtx_unlock(&u->mutex);
431	return (len - ib->buflen);
432}
433
434static int
435pio_odata(struct upd7210 *u, u_char *data, int len)
436{
437	struct ibfoo *ib;
438
439	ib = u->ibfoo;
440
441	if (len == 0)
442		return (0);
443	mtx_lock(&u->mutex);
444	ib->buf = data;
445	ib->buflen = len;
446	if (u->use_fifo) {
447		/* TNT5004 or TNT4882 in FIFO mode */
448		ib->mode = FIFO_ODATA;
449		bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */
450		if (ib->doeoi)
451			bus_write_1(u->reg_res[0], cfg, 0x08); /* CCEN */
452		else
453			bus_write_1(u->reg_res[0], cfg, 0x00); /* xfer OUT, 8-bit FIFO */
454		bus_write_1(u->reg_res[0], imr3, 0x19); /* STOP IE, NFF IE, DONE IE */
455		bus_write_1(u->reg_res[0], cnt0, -len);
456		bus_write_1(u->reg_res[0], cnt1, (-len) >> 8);
457		bus_write_1(u->reg_res[0], cnt2, (-len) >> 16);
458		bus_write_1(u->reg_res[0], cnt3, (-len) >> 24);
459		bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */
460	} else {
461		ib->mode = PIO_ODATA;
462		upd7210_wr(u, IMR1, IXR1_DO);
463	}
464
465	gpib_ib_wait_xfer(u, ib);
466
467	if (u->use_fifo)
468		bus_write_1(u->reg_res[0], cmdr, 0x08); /* STOP */
469
470	mtx_unlock(&u->mutex);
471	return (len - ib->buflen);
472}
473
474static int
475pio_idata(struct upd7210 *u, u_char *data, int len)
476{
477	struct ibfoo *ib;
478
479	ib = u->ibfoo;
480
481	mtx_lock(&u->mutex);
482	ib->buf = data;
483	ib->buflen = len;
484	if (u->use_fifo) {
485		/* TNT5004 or TNT4882 in FIFO mode */
486		ib->mode = FIFO_IDATA;
487		bus_write_1(u->reg_res[0], cmdr, 0x10); /* reset FIFO */
488		bus_write_1(u->reg_res[0], cfg, 0x20); /* xfer IN, 8-bit FIFO */
489		bus_write_1(u->reg_res[0], cnt0, -len);
490		bus_write_1(u->reg_res[0], cnt1, (-len) >> 8);
491		bus_write_1(u->reg_res[0], cnt2, (-len) >> 16);
492		bus_write_1(u->reg_res[0], cnt3, (-len) >> 24);
493		bus_write_1(u->reg_res[0], cmdr, 0x04); /* GO */
494		upd7210_wr(u, AUXMR, AUXMR_RFD);
495		bus_write_1(u->reg_res[0], imr3, 0x15); /* STOP IE, NEF IE, DONE IE */
496	} else {
497		ib->mode = PIO_IDATA;
498		upd7210_wr(u, IMR1, IXR1_DI);
499	}
500
501	gpib_ib_wait_xfer(u, ib);
502
503	if (u->use_fifo)
504		bus_write_1(u->reg_res[0], cmdr, 0x08); /* STOP */
505
506	mtx_unlock(&u->mutex);
507	return (len - ib->buflen);
508}
509
510static int
511dma_idata(struct upd7210 *u, u_char *data, int len)
512{
513	int j;
514	struct ibfoo *ib;
515
516	KASSERT(u->dmachan >= 0, ("Bogus dmachan %d", u->dmachan));
517	ib = u->ibfoo;
518	ib->mode = DMA_IDATA;
519	isa_dmastart(ISADMA_READ, data, len, u->dmachan);
520	mtx_lock(&u->mutex);
521	upd7210_wr(u, IMR1, IXR1_ENDRX);
522	upd7210_wr(u, IMR2, IMR2_DMAI);
523	gpib_ib_wait_xfer(u, ib);
524	mtx_unlock(&u->mutex);
525	j = isa_dmastatus(u->dmachan);
526	isa_dmadone(ISADMA_READ, data, len, u->dmachan);
527	return (len - j);
528}
529
530static int
531ib_send_msg(struct ibfoo *ib, int msg)
532{
533	u_char buf[10];
534	int i, j;
535
536	i = 0;
537	buf[i++] = UNT;
538	buf[i++] = UNL;
539	buf[i++] = LAD | ib->h->pad;
540	if (ib->h->sad)
541		buf[i++] = LAD | TAD | ib->h->sad;
542	buf[i++] = TAD | 0;
543	buf[i++] = msg;
544	j = pio_cmd(ib->u, buf, i);
545	if (i != j)
546		ib_set_error(ib->ap, EABO); /* XXX ? */
547	return (0);
548}
549
550static int
551ibask(struct ibfoo *ib)
552{	/* XXX */
553
554	ibdebug = ib->ap->option;
555	return (0);
556}
557
558#define ibbna NULL
559#define ibcac NULL
560
561static int
562ibclr(struct ibfoo *ib)
563{
564
565	return (ib_send_msg(ib, SDC));
566}
567
568#define ibcmd NULL
569#define ibcmda NULL
570#define ibconfig NULL
571
572static int
573ibdev(struct ibfoo *ib)
574{	/* TBD */
575	struct handle *h;
576
577	h = malloc(sizeof *h, M_IBFOO, M_ZERO | M_WAITOK);
578	h->handle = alloc_unr(ib->unrhdr);
579	h->kind = H_DEV;
580	h->pad = ib->ap->pad;
581	h->sad = ib->ap->sad;
582	h->timeout = timeouts[ib->ap->tmo];
583	h->eot = ib->ap->eot;
584	h->eos = ib->ap->eos;
585	mtx_lock(&ib->u->mutex);
586	LIST_INSERT_HEAD(&ib->handles, h, list);
587	mtx_unlock(&ib->u->mutex);
588	ib->ap->__retval = h->handle;
589	return (0);
590}
591
592#define ibdiag NULL
593
594static int
595ibdma(struct ibfoo *ib)
596{
597
598	if (ib->u->dmachan < 0 && ib->ap->v)
599		return (ib_set_error(ib->ap, EARG));
600	ib->h->dma = ib->ap->v;
601	return (0);
602}
603
604static int
605ibeos(struct ibfoo *ib)
606{
607
608	ib->ap->__iberr = ib->h->eos;
609	ib->h->eos = ib->ap->eos;
610	if (ib->rdh == ib->h)
611		config_eos(ib->u, ib->h);
612	return (0);
613}
614
615static int
616ibeot(struct ibfoo *ib)
617{
618
619	ib->h->eot = ib->ap->eot;
620	return (0);
621}
622
623#define ibevent NULL
624#define ibfind NULL
625#define ibgts NULL
626#define ibist NULL
627#define iblines NULL
628#define ibllo NULL
629#define ibln NULL
630
631static int
632ibloc(struct ibfoo *ib)
633{	/* XXX */
634
635	if (ib->h->kind == H_BOARD)
636		return (EOPNOTSUPP); /* XXX */
637	return (ib_send_msg(ib, GTL));
638}
639
640static int
641ibonl(struct ibfoo *ib)
642{	/* XXX */
643
644	if (ib->ap->v)
645		return (EOPNOTSUPP);	/* XXX */
646	mtx_lock(&ib->u->mutex);
647	LIST_REMOVE(ib->h, list);
648	mtx_unlock(&ib->u->mutex);
649	free(ib->h, M_IBFOO);
650	ib->h = NULL;
651	return (0);
652}
653
654static int
655ibpad(struct ibfoo *ib)
656{
657
658	ib->h->pad = ib->ap->pad;
659	return (0);
660}
661
662#define ibpct NULL
663#define ibpoke NULL
664#define ibppc NULL
665
666static int
667ibrd(struct ibfoo *ib)
668{	/* TBD */
669	u_char buf[10], *bp;
670	int i, j, error, bl, bc;
671	u_char *dp;
672
673	if (ib->h->kind == H_BOARD)
674		return (EOPNOTSUPP); /* XXX */
675	bl = ib->ap->cnt;
676	if (bl > PAGE_SIZE)
677		bl = PAGE_SIZE;
678	bp = malloc(bl, M_IBFOO, M_WAITOK);
679
680	if (ib->rdh != ib->h) {
681		i = 0;
682		buf[i++] = UNT;
683		buf[i++] = UNL;
684		buf[i++] = LAD | 0;
685		buf[i++] = TAD | ib->h->pad;
686		if (ib->h->sad)
687			buf[i++] = ib->h->sad;
688		i = pio_cmd(ib->u, buf, i);
689		config_eos(ib->u, ib->h);
690		ib->rdh = ib->h;
691		ib->wrh = NULL;
692	}
693	upd7210_goto_standby(ib->u);
694	dp = ib->ap->buffer;
695	bc = ib->ap->cnt;
696	error = 0;
697	while (bc > 0 && ib->ap->__iberr == 0) {
698		j = imin(bc, PAGE_SIZE);
699		if (ib->h->dma)
700			i = dma_idata(ib->u, bp, j);
701		else
702			i = pio_idata(ib->u, bp, j);
703		error = copyout(bp, dp , i);
704		if (error)
705			break;
706		ib->ap->__ibcnt += i;
707		if (i != j)
708			break;
709		bc -= i;
710		dp += i;
711	}
712	upd7210_take_ctrl_async(ib->u);
713	free(bp, M_IBFOO);
714	return (error);
715}
716
717#define ibrda NULL
718#define ibrdf NULL
719#define ibrdkey NULL
720#define ibrpp NULL
721#define ibrsc NULL
722#define ibrsp NULL
723#define ibrsv NULL
724
725static int
726ibsad(struct ibfoo *ib)
727{
728
729	ib->h->sad = ib->ap->sad;
730	return (0);
731}
732
733#define ibsgnl NULL
734
735static int
736ibsic(struct ibfoo *ib)
737{	/* TBD */
738
739	upd7210_wr(ib->u, AUXMR, AUXMR_SIFC);
740	DELAY(100);
741	upd7210_wr(ib->u, AUXMR, AUXMR_CIFC);
742	return (0);
743}
744
745#define ibsre NULL
746#define ibsrq NULL
747#define ibstop NULL
748
749static int
750ibtmo(struct ibfoo *ib)
751{
752
753	ib->h->timeout = timeouts[ib->ap->tmo];
754	return (0);
755}
756
757#define ibtrap NULL
758
759static int
760ibtrg(struct ibfoo *ib)
761{
762
763	return (ib_send_msg(ib, GET));
764}
765
766#define ibwait NULL
767
768static int
769ibwrt(struct ibfoo *ib)
770{	/* XXX */
771	u_char buf[10], *bp;
772	int i;
773
774	if (ib->h->kind == H_BOARD)
775		return (EOPNOTSUPP);
776	bp = malloc(ib->ap->cnt, M_IBFOO, M_WAITOK);
777	/* XXX: bigger than PAGE_SIZE handling */
778	i = copyin(ib->ap->buffer, bp, ib->ap->cnt);
779	if (i) {
780		free(bp, M_IBFOO);
781		return (i);
782	}
783	if (ib->wrh != ib->h) {
784		i = 0;
785		buf[i++] = UNT;
786		buf[i++] = UNL;
787		buf[i++] = LAD | ib->h->pad;
788		if (ib->h->sad)
789			buf[i++] = LAD | TAD | ib->h->sad;
790		buf[i++] = TAD | 0;
791		i = pio_cmd(ib->u, buf, i);
792		ib->rdh = NULL;
793		ib->wrh = ib->h;
794		config_eos(ib->u, ib->h);
795	}
796	upd7210_goto_standby(ib->u);
797	ib->doeoi = ib->h->eot;
798	i = pio_odata(ib->u, bp, ib->ap->cnt);
799	upd7210_take_ctrl_async(ib->u);
800	ib->ap->__ibcnt = i;
801	free(bp, M_IBFOO);
802	return (0);
803}
804
805#define ibwrta NULL
806#define ibwrtf NULL
807#define ibwrtkey NULL
808#define ibxtrc NULL
809
810static struct ibhandler {
811	const char 	*name;
812	enum h_kind	kind;
813	ibhandler_t	*func;
814	u_int		args;
815} ibhandlers[] = {
816	[__ID_IBASK] =		{ "ibask",	H_EITHER,	ibask,		__F_HANDLE | __F_OPTION | __F_RETVAL },
817	[__ID_IBBNA] =		{ "ibbna",	H_DEV,		ibbna,		__F_HANDLE | __F_BDNAME },
818	[__ID_IBCAC] =		{ "ibcac",	H_BOARD,	ibcac,		__F_HANDLE | __F_V },
819	[__ID_IBCLR] =		{ "ibclr",	H_DEV,		ibclr,		__F_HANDLE },
820	[__ID_IBCMD] =		{ "ibcmd",	H_BOARD,	ibcmd,		__F_HANDLE | __F_BUFFER | __F_CNT },
821	[__ID_IBCMDA] =		{ "ibcmda",	H_BOARD,	ibcmda,		__F_HANDLE | __F_BUFFER | __F_CNT },
822	[__ID_IBCONFIG] =	{ "ibconfig",	H_EITHER,	ibconfig,	__F_HANDLE | __F_OPTION | __F_VALUE },
823	[__ID_IBDEV] =		{ "ibdev",	0,		ibdev,		__F_BOARDID | __F_PAD | __F_SAD | __F_TMO | __F_EOT | __F_EOS },
824	[__ID_IBDIAG] =		{ "ibdiag",	H_EITHER,	ibdiag,		__F_HANDLE | __F_BUFFER | __F_CNT },
825	[__ID_IBDMA] =		{ "ibdma",	H_EITHER,	ibdma,		__F_HANDLE | __F_V },
826	[__ID_IBEOS] =		{ "ibeos",	H_EITHER,	ibeos,		__F_HANDLE | __F_EOS },
827	[__ID_IBEOT] =		{ "ibeot",	H_EITHER,	ibeot,		__F_HANDLE | __F_EOT },
828	[__ID_IBEVENT] =	{ "ibevent",	H_BOARD,	ibevent,	__F_HANDLE | __F_EVENT },
829	[__ID_IBFIND] =		{ "ibfind",	0,		ibfind,		__F_BDNAME },
830	[__ID_IBGTS] =		{ "ibgts",	H_BOARD,	ibgts,		__F_HANDLE | __F_V },
831	[__ID_IBIST] =		{ "ibist",	H_BOARD,	ibist,		__F_HANDLE | __F_V },
832	[__ID_IBLINES] =	{ "iblines",	H_BOARD,	iblines,	__F_HANDLE | __F_LINES },
833	[__ID_IBLLO] =		{ "ibllo",	H_EITHER,	ibllo,		__F_HANDLE },
834	[__ID_IBLN] =		{ "ibln",	H_BOARD,	ibln,		__F_HANDLE | __F_PADVAL | __F_SADVAL | __F_LISTENFLAG },
835	[__ID_IBLOC] =		{ "ibloc",	H_EITHER,	ibloc,		__F_HANDLE },
836	[__ID_IBONL] =		{ "ibonl",	H_EITHER,	ibonl,		__F_HANDLE | __F_V },
837	[__ID_IBPAD] =		{ "ibpad",	H_EITHER,	ibpad,		__F_HANDLE | __F_PAD },
838	[__ID_IBPCT] =		{ "ibpct",	H_DEV,		ibpct,		__F_HANDLE },
839	[__ID_IBPOKE] =		{ "ibpoke",	H_EITHER,	ibpoke,		__F_HANDLE | __F_OPTION | __F_VALUE },
840	[__ID_IBPPC] =		{ "ibppc",	H_EITHER,	ibppc,		__F_HANDLE | __F_V },
841	[__ID_IBRD] =		{ "ibrd",	H_EITHER,	ibrd,		__F_HANDLE | __F_BUFFER | __F_CNT },
842	[__ID_IBRDA] =		{ "ibrda",	H_EITHER,	ibrda,		__F_HANDLE | __F_BUFFER | __F_CNT },
843	[__ID_IBRDF] =		{ "ibrdf",	H_EITHER,	ibrdf,		__F_HANDLE | __F_FLNAME },
844	[__ID_IBRDKEY] =	{ "ibrdkey",	H_EITHER,	ibrdkey,	__F_HANDLE | __F_BUFFER | __F_CNT },
845	[__ID_IBRPP] =		{ "ibrpp",	H_EITHER,	ibrpp,		__F_HANDLE | __F_PPR },
846	[__ID_IBRSC] =		{ "ibrsc",	H_BOARD,	ibrsc,		__F_HANDLE | __F_V },
847	[__ID_IBRSP] =		{ "ibrsp",	H_DEV,		ibrsp,		__F_HANDLE | __F_SPR },
848	[__ID_IBRSV] =		{ "ibrsv",	H_EITHER,	ibrsv,		__F_HANDLE | __F_V },
849	[__ID_IBSAD] =		{ "ibsad",	H_EITHER,	ibsad,		__F_HANDLE | __F_SAD },
850	[__ID_IBSGNL] =		{ "ibsgnl",	H_EITHER,	ibsgnl,		__F_HANDLE | __F_V },
851	[__ID_IBSIC] =		{ "ibsic",	H_BOARD,	ibsic,		__F_HANDLE },
852	[__ID_IBSRE] =		{ "ibsre",	H_BOARD,	ibsre,		__F_HANDLE | __F_V },
853	[__ID_IBSRQ] =		{ "ibsrq",	H_EITHER,	ibsrq,		__F_FUNC },
854	[__ID_IBSTOP] =		{ "ibstop",	H_EITHER,	ibstop,		__F_HANDLE },
855	[__ID_IBTMO] =		{ "ibtmo",	H_EITHER,	ibtmo,		__F_HANDLE | __F_TMO },
856	[__ID_IBTRAP] =		{ "ibtrap",	H_EITHER,	ibtrap,		__F_MASK | __F_MODE },
857	[__ID_IBTRG] =		{ "ibtrg",	H_DEV,		ibtrg,		__F_HANDLE },
858	[__ID_IBWAIT] =		{ "ibwait",	H_EITHER,	ibwait,		__F_HANDLE | __F_MASK },
859	[__ID_IBWRT] =		{ "ibwrt",	H_EITHER,	ibwrt,		__F_HANDLE | __F_BUFFER | __F_CNT },
860	[__ID_IBWRTA] =		{ "ibwrta",	H_EITHER,	ibwrta,		__F_HANDLE | __F_BUFFER | __F_CNT },
861	[__ID_IBWRTF] =		{ "ibwrtf",	H_EITHER,	ibwrtf,		__F_HANDLE | __F_FLNAME },
862	[__ID_IBWRTKEY] =	{ "ibwrtkey",	H_EITHER,	ibwrtkey,	__F_HANDLE | __F_BUFFER | __F_CNT },
863	[__ID_IBXTRC] =		{ "ibxtrc",	H_EITHER,	ibxtrc,		__F_HANDLE | __F_BUFFER | __F_CNT },
864};
865
866static const u_int max_ibhandler = sizeof ibhandlers / sizeof ibhandlers[0];
867
868static void
869ib_dump_args(struct ibhandler *ih, struct ibarg *ap)
870{
871
872	if (ih->name != NULL)
873		printf("%s(", ih->name);
874	else
875		printf("ibinvalid(");
876	printf("[0x%x]", ap->__field);
877	if (ap->__field & __F_HANDLE)	printf(" handle=%d", ap->handle);
878	if (ap->__field & __F_EOS)	printf(" eos=0x%x", ap->eos);
879	if (ap->__field & __F_EOT)	printf(" eot=%d", ap->eot);
880	if (ap->__field & __F_TMO)	printf(" tmo=%d", ap->tmo);
881	if (ap->__field & __F_PAD)	printf(" pad=0x%x", ap->pad);
882	if (ap->__field & __F_SAD)	printf(" sad=0x%x", ap->sad);
883	if (ap->__field & __F_BUFFER)	printf(" buffer=%p", ap->buffer);
884	if (ap->__field & __F_CNT)	printf(" cnt=%ld", ap->cnt);
885	if (ap->__field & __F_V)	printf(" v=%d/0x%x", ap->v, ap->v);
886	/* XXX more ... */
887	printf(")\n");
888}
889
890static int
891gpib_ib_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
892{
893	struct upd7210 *u;
894	struct ibfoo *ib;
895	int error = 0;
896
897	u = dev->si_drv1;
898
899	mtx_lock(&u->mutex);
900	if (u->busy) {
901		mtx_unlock(&u->mutex);
902		return (EBUSY);
903	}
904	u->busy = 1;
905	mtx_unlock(&u->mutex);
906
907	if (u->dmachan >= 0) {
908		error = isa_dma_acquire(u->dmachan);
909		if (!error) {
910			error = isa_dma_init(u->dmachan, PAGE_SIZE, M_WAITOK);
911			if (error)
912				isa_dma_release(u->dmachan);
913		}
914	}
915
916	if (error) {
917		mtx_lock(&u->mutex);
918		u->busy = 0;
919		mtx_unlock(&u->mutex);
920		return (error);
921	}
922
923	ib = malloc(sizeof *ib, M_IBFOO, M_WAITOK | M_ZERO);
924	LIST_INIT(&ib->handles);
925	callout_init(&ib->callout, CALLOUT_MPSAFE);
926	ib->unrhdr = new_unrhdr(0, INT_MAX, NULL);
927	dev->si_drv2 = ib;
928	ib->u = u;
929	u->ibfoo = ib;
930	u->irq = gpib_ib_irq;
931
932	upd7210_wr(u, AUXMR, AUXMR_CRST);
933	DELAY(10000);
934	DELAY(1000);
935	upd7210_wr(u, IMR1, 0x00);
936	upd7210_wr(u, IMR2, 0x00);
937	upd7210_wr(u, SPMR, 0x00);
938	upd7210_wr(u, ADR, 0x00);
939	upd7210_wr(u, ADR, ADR_ARS | ADR_DL | ADR_DT);
940	upd7210_wr(u, ADMR, ADMR_ADM0 | ADMR_TRM0 | ADMR_TRM1);
941	upd7210_wr(u, EOSR, 0x00);
942	upd7210_wr(u, AUXMR, C_ICR | 8);
943	upd7210_wr(u, AUXMR, C_PPR | PPR_U);
944	upd7210_wr(u, AUXMR, C_AUXA);
945	upd7210_wr(u, AUXMR, C_AUXB + 3);
946	upd7210_wr(u, AUXMR, C_AUXE + 0);
947	upd7210_wr(u, AUXMR, AUXMR_PON);
948	if (u->use_fifo) {
949		bus_write_1(u->reg_res[0], imr3, 0x00);
950		bus_write_1(u->reg_res[0], cmdr, 0x22); /* soft reset */
951		bus_write_1(u->reg_res[0], cmdr, 0x03); /* set system
952							 * controller bit */
953	}
954	upd7210_wr(u, AUXMR, AUXMR_CIFC);
955	DELAY(100);
956	upd7210_wr(u, AUXMR, AUXMR_SIFC);
957	upd7210_wr(u, AUXMR, AUXMR_SREN);
958	return (0);
959}
960
961static int
962gpib_ib_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
963{
964	struct upd7210 *u;
965	struct ibfoo *ib;
966
967	u = dev->si_drv1;
968	ib = dev->si_drv2;
969	/* XXX: assert pointer consistency */
970
971	u->ibfoo = NULL;
972	/* XXX: free handles */
973	dev->si_drv2 = NULL;
974	free(ib, M_IBFOO);
975
976	if (u->dmachan >= 0) {
977		isa_dma_release(u->dmachan);
978	}
979	mtx_lock(&u->mutex);
980	u->busy = 0;
981	ibdebug = 0;
982	upd7210_wr(u, IMR1, 0x00);
983	upd7210_wr(u, IMR2, 0x00);
984	if (u->use_fifo) {
985		bus_write_1(u->reg_res[0], imr3, 0x00);
986		bus_write_1(u->reg_res[0], cmdr, 0x02); /* clear system
987							 * controller bit */
988	}
989	upd7210_wr(u, AUXMR, AUXMR_CRST);
990	DELAY(10000);
991	mtx_unlock(&u->mutex);
992	return (0);
993}
994
995static int
996gpib_ib_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
997{
998	struct ibarg *ap;
999	struct ibhandler *ih;
1000	struct handle *h;
1001	struct upd7210 *u;
1002	struct ibfoo *ib;
1003	int error;
1004	struct timeval deadline, tv;
1005
1006	u = dev->si_drv1;
1007	ib = u->ibfoo;
1008
1009	/* We only support a single ioctl, everything else is a mistake */
1010	if (cmd != GPIB_IBFOO)
1011		return (ENOIOCTL);
1012
1013	/* Check the identifier and field-bitmap in the arguments.  */
1014	ap = (void *)data;
1015	if (ap->__ident < 0 || ap->__ident >= max_ibhandler)
1016		return (EINVAL);
1017	ih = &ibhandlers[ap->__ident];
1018	if (ap->__field != ih->args)
1019		return (EINVAL);
1020
1021	if (ibdebug)
1022		ib_dump_args(ih, ap);
1023
1024	if (ih->func == NULL)
1025		return (EOPNOTSUPP);
1026
1027	ap->__iberr = 0;
1028	ap->__ibsta = 0;
1029	ap->__ibcnt = 0;
1030	ap->__retval = 0;
1031
1032	if (ap->__field & __F_TMO) {
1033		if (ap->tmo < 0 || ap->tmo >= max_timeouts)
1034			return (ib_set_error(ap, EARG));
1035	}
1036
1037	if (ap->__field & __F_EOS) {
1038		if ((ap->eos & ~(REOS | XEOS | BIN | 0xff)) ||
1039		    ((ap->eos & (BIN | 0x80)) == 0x80))
1040			return (ib_set_error(ap, EARG));
1041	}
1042	if (ap->__field & __F_PAD) {
1043		if (ap->pad < 0 || ap->pad > 30)
1044			return (ib_set_error(ap, EARG));
1045	}
1046	if (ap->__field & __F_SAD) {
1047		if (ap->sad != 0 && (ap->sad < 0x60 || ap->sad > 126))
1048			return (ib_set_error(ap, EARG));
1049	}
1050
1051
1052	mtx_lock(&u->mutex);
1053
1054
1055	/* Find the handle, if any */
1056	h = NULL;
1057	if ((ap->__field & __F_HANDLE) && gethandle(u, ap, &h)) {
1058		mtx_unlock(&u->mutex);
1059		return (0);
1060	}
1061
1062	/* Check that the handle is the right kind */
1063	if (h != NULL && !(h->kind & ih->kind)) {
1064		mtx_unlock(&u->mutex);
1065		return (ib_set_error(ap, EARG));
1066	}
1067
1068	/* Set up handle and deadline */
1069	if (h != NULL && timevalisset(&h->timeout)) {
1070		getmicrouptime(&deadline);
1071		timevaladd(&deadline, &h->timeout);
1072	} else {
1073		timevalclear(&deadline);
1074	}
1075
1076	/* Wait for the card to be(come) available, respect deadline */
1077	while(u->busy != 1) {
1078		error = msleep(ib, &u->mutex,
1079		    PZERO | PCATCH, "gpib_ibioctl", hz / 10);
1080		if (error == 0)
1081			continue;
1082		mtx_unlock(&u->mutex);
1083		if (error == EINTR)
1084			return(ib_set_error(ap, EABO));
1085		if (error == EWOULDBLOCK && timevalisset(&deadline)) {
1086			getmicrouptime(&tv);
1087			if (timevalcmp(&deadline, &tv, <))
1088				return(ib_had_timeout(ap));
1089		}
1090		mtx_lock(&u->mutex);
1091	}
1092	u->busy = 2;
1093	mtx_unlock(&u->mutex);
1094
1095	/* Hand over deadline handling to the callout routine */
1096	ib->ap = ap;
1097	ib->h = h;
1098	ib->mode = BUSY;
1099	ib->deadline = deadline;
1100	callout_reset(&ib->callout, hz / 5, gpib_ib_timeout, u);
1101
1102	error = ih->func(ib);
1103
1104	/* Release card */
1105	ib->mode = IDLE;
1106	ib->ap = NULL;
1107	ib->h = NULL;
1108	timevalclear(&deadline);
1109	callout_stop(&ib->callout);
1110
1111	mtx_lock(&u->mutex);
1112	u->busy = 1;
1113	wakeup(ib);
1114	mtx_unlock(&u->mutex);
1115
1116	if (error)
1117		return(ib_set_errno(ap, error));
1118	return (0);
1119}
1120
1121struct cdevsw gpib_ib_cdevsw = {
1122	.d_version =	D_VERSION,
1123	.d_name =	"gpib_ib",
1124	.d_open	=	gpib_ib_open,
1125	.d_ioctl =	gpib_ib_ioctl,
1126	.d_close =	gpib_ib_close,
1127};
1128