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