ibfoo.c revision 178250
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 178250 2008-04-16 16:47:14Z kris $");
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	mtx_lock(&Giant);
401	isa_dmastart(ISADMA_READ, data, len, u->dmachan);
402	mtx_unlock(&Giant);
403	mtx_lock(&u->mutex);
404	upd7210_wr(u, IMR1, IXR1_ENDRX);
405	upd7210_wr(u, IMR2, IMR2_DMAI);
406	gpib_ib_wait_xfer(u, ib);
407	mtx_unlock(&u->mutex);
408	mtx_lock(&Giant);
409	j = isa_dmastatus(u->dmachan);
410	isa_dmadone(ISADMA_READ, data, len, u->dmachan);
411	mtx_unlock(&Giant);
412	return (len - j);
413}
414
415static int
416ib_send_msg(struct ibfoo *ib, int msg)
417{
418	u_char buf[10];
419	int i, j;
420
421	i = 0;
422	buf[i++] = UNT;
423	buf[i++] = UNL;
424	buf[i++] = LAD | ib->h->pad;
425	if (ib->h->sad)
426		buf[i++] = LAD | TAD | ib->h->sad;
427	buf[i++] = TAD | 0;
428	buf[i++] = msg;
429	j = pio_cmd(ib->u, buf, i);
430	if (i != j)
431		ib_set_error(ib->ap, EABO); /* XXX ? */
432	return (0);
433}
434
435static int
436ibask(struct ibfoo *ib)
437{	/* XXX */
438
439	ibdebug = ib->ap->option;
440	return (0);
441}
442
443#define ibbna NULL
444#define ibcac NULL
445
446static int
447ibclr(struct ibfoo *ib)
448{
449
450	return (ib_send_msg(ib, SDC));
451}
452
453#define ibcmd NULL
454#define ibcmda NULL
455#define ibconfig NULL
456
457static int
458ibdev(struct ibfoo *ib)
459{	/* TBD */
460	struct handle *h;
461
462	h = malloc(sizeof *h, M_IBFOO, M_ZERO | M_WAITOK);
463	h->handle = alloc_unr(ib->unrhdr);
464	h->kind = H_DEV;
465	h->pad = ib->ap->pad;
466	h->sad = ib->ap->sad;
467	h->timeout = timeouts[ib->ap->tmo];
468	h->eot = ib->ap->eot;
469	h->eos = ib->ap->eos;
470	mtx_lock(&ib->u->mutex);
471	LIST_INSERT_HEAD(&ib->handles, h, list);
472	mtx_unlock(&ib->u->mutex);
473	ib->ap->__retval = h->handle;
474	return (0);
475}
476
477#define ibdiag NULL
478
479static int
480ibdma(struct ibfoo *ib)
481{
482
483	if (ib->u->dmachan < 0 && ib->ap->v)
484		return (ib_set_error(ib->ap, EARG));
485	ib->h->dma = ib->ap->v;
486	return (0);
487}
488
489static int
490ibeos(struct ibfoo *ib)
491{
492
493	ib->ap->__iberr = ib->h->eos;
494	ib->h->eos = ib->ap->eos;
495	if (ib->rdh == ib->h)
496		config_eos(ib->u, ib->h);
497	return (0);
498}
499
500static int
501ibeot(struct ibfoo *ib)
502{
503
504	ib->h->eot = ib->ap->eot;
505	return (0);
506}
507
508#define ibevent NULL
509#define ibfind NULL
510#define ibgts NULL
511#define ibist NULL
512#define iblines NULL
513#define ibllo NULL
514#define ibln NULL
515
516static int
517ibloc(struct ibfoo *ib)
518{	/* XXX */
519
520	if (ib->h->kind == H_BOARD)
521		return (EOPNOTSUPP); /* XXX */
522	return (ib_send_msg(ib, GTL));
523}
524
525static int
526ibonl(struct ibfoo *ib)
527{	/* XXX */
528
529	if (ib->ap->v)
530		return (EOPNOTSUPP);	/* XXX */
531	mtx_lock(&ib->u->mutex);
532	LIST_REMOVE(ib->h, list);
533	mtx_unlock(&ib->u->mutex);
534	free(ib->h, M_IBFOO);
535	ib->h = NULL;
536	return (0);
537}
538
539static int
540ibpad(struct ibfoo *ib)
541{
542
543	ib->h->pad = ib->ap->pad;
544	return (0);
545}
546
547#define ibpct NULL
548#define ibpoke NULL
549#define ibppc NULL
550
551static int
552ibrd(struct ibfoo *ib)
553{	/* TBD */
554	u_char buf[10], *bp;
555	int i, j, error, bl, bc;
556	u_char *dp;
557
558	if (ib->h->kind == H_BOARD)
559		return (EOPNOTSUPP); /* XXX */
560	bl = ib->ap->cnt;
561	if (bl > PAGE_SIZE)
562		bl = PAGE_SIZE;
563	bp = malloc(bl, M_IBFOO, M_WAITOK);
564
565	if (ib->rdh != ib->h) {
566		i = 0;
567		buf[i++] = UNT;
568		buf[i++] = UNL;
569		buf[i++] = LAD | 0;
570		buf[i++] = TAD | ib->h->pad;
571		if (ib->h->sad)
572			buf[i++] = ib->h->sad;
573		i = pio_cmd(ib->u, buf, i);
574		config_eos(ib->u, ib->h);
575		ib->rdh = ib->h;
576		ib->wrh = NULL;
577	}
578	upd7210_goto_standby(ib->u);
579	dp = ib->ap->buffer;
580	bc = ib->ap->cnt;
581	error = 0;
582	while (bc > 0 && ib->ap->__iberr == 0) {
583		j = imin(bc, PAGE_SIZE);
584		if (ib->h->dma)
585			i = dma_idata(ib->u, bp, j);
586		else
587			i = pio_idata(ib->u, bp, j);
588		error = copyout(bp, dp , i);
589		if (error)
590			break;
591		ib->ap->__ibcnt += i;
592		if (i != j)
593			break;
594		bc -= i;
595		dp += i;
596	}
597	upd7210_take_ctrl_async(ib->u);
598	free(bp, M_IBFOO);
599	return (error);
600}
601
602#define ibrda NULL
603#define ibrdf NULL
604#define ibrdkey NULL
605#define ibrpp NULL
606#define ibrsc NULL
607#define ibrsp NULL
608#define ibrsv NULL
609
610static int
611ibsad(struct ibfoo *ib)
612{
613
614	ib->h->sad = ib->ap->sad;
615	return (0);
616}
617
618#define ibsgnl NULL
619
620static int
621ibsic(struct ibfoo *ib)
622{	/* TBD */
623
624	upd7210_wr(ib->u, AUXMR, AUXMR_SIFC);
625	DELAY(100);
626	upd7210_wr(ib->u, AUXMR, AUXMR_CIFC);
627	return (0);
628}
629
630#define ibsre NULL
631#define ibsrq NULL
632#define ibstop NULL
633
634static int
635ibtmo(struct ibfoo *ib)
636{
637
638	ib->h->timeout = timeouts[ib->ap->tmo];
639	return (0);
640}
641
642#define ibtrap NULL
643
644static int
645ibtrg(struct ibfoo *ib)
646{
647
648	return (ib_send_msg(ib, GET));
649}
650
651#define ibwait NULL
652
653static int
654ibwrt(struct ibfoo *ib)
655{	/* XXX */
656	u_char buf[10], *bp;
657	int i;
658
659	if (ib->h->kind == H_BOARD)
660		return (EOPNOTSUPP);
661	bp = malloc(ib->ap->cnt, M_IBFOO, M_WAITOK);
662	/* XXX: bigger than PAGE_SIZE handling */
663	i = copyin(ib->ap->buffer, bp, ib->ap->cnt);
664	if (i) {
665		free(bp, M_IBFOO);
666		return (i);
667	}
668	if (ib->wrh != ib->h) {
669		i = 0;
670		buf[i++] = UNT;
671		buf[i++] = UNL;
672		buf[i++] = LAD | ib->h->pad;
673		if (ib->h->sad)
674			buf[i++] = LAD | TAD | ib->h->sad;
675		buf[i++] = TAD | 0;
676		i = pio_cmd(ib->u, buf, i);
677		ib->rdh = NULL;
678		ib->wrh = ib->h;
679		config_eos(ib->u, ib->h);
680	}
681	upd7210_goto_standby(ib->u);
682	ib->doeoi = ib->h->eot;
683	i = pio_odata(ib->u, bp, ib->ap->cnt);
684	upd7210_take_ctrl_async(ib->u);
685	ib->ap->__ibcnt = i;
686	free(bp, M_IBFOO);
687	return (0);
688}
689
690#define ibwrta NULL
691#define ibwrtf NULL
692#define ibwrtkey NULL
693#define ibxtrc NULL
694
695static struct ibhandler {
696	const char 	*name;
697	enum h_kind	kind;
698	ibhandler_t	*func;
699	u_int		args;
700} ibhandlers[] = {
701	[__ID_IBASK] =		{ "ibask",	H_EITHER,	ibask,		__F_HANDLE | __F_OPTION | __F_RETVAL },
702	[__ID_IBBNA] =		{ "ibbna",	H_DEV,		ibbna,		__F_HANDLE | __F_BDNAME },
703	[__ID_IBCAC] =		{ "ibcac",	H_BOARD,	ibcac,		__F_HANDLE | __F_V },
704	[__ID_IBCLR] =		{ "ibclr",	H_DEV,		ibclr,		__F_HANDLE },
705	[__ID_IBCMD] =		{ "ibcmd",	H_BOARD,	ibcmd,		__F_HANDLE | __F_BUFFER | __F_CNT },
706	[__ID_IBCMDA] =		{ "ibcmda",	H_BOARD,	ibcmda,		__F_HANDLE | __F_BUFFER | __F_CNT },
707	[__ID_IBCONFIG] =	{ "ibconfig",	H_EITHER,	ibconfig,	__F_HANDLE | __F_OPTION | __F_VALUE },
708	[__ID_IBDEV] =		{ "ibdev",	0,		ibdev,		__F_BOARDID | __F_PAD | __F_SAD | __F_TMO | __F_EOT | __F_EOS },
709	[__ID_IBDIAG] =		{ "ibdiag",	H_EITHER,	ibdiag,		__F_HANDLE | __F_BUFFER | __F_CNT },
710	[__ID_IBDMA] =		{ "ibdma",	H_EITHER,	ibdma,		__F_HANDLE | __F_V },
711	[__ID_IBEOS] =		{ "ibeos",	H_EITHER,	ibeos,		__F_HANDLE | __F_EOS },
712	[__ID_IBEOT] =		{ "ibeot",	H_EITHER,	ibeot,		__F_HANDLE | __F_EOT },
713	[__ID_IBEVENT] =	{ "ibevent",	H_BOARD,	ibevent,	__F_HANDLE | __F_EVENT },
714	[__ID_IBFIND] =		{ "ibfind",	0,		ibfind,		__F_BDNAME },
715	[__ID_IBGTS] =		{ "ibgts",	H_BOARD,	ibgts,		__F_HANDLE | __F_V },
716	[__ID_IBIST] =		{ "ibist",	H_BOARD,	ibist,		__F_HANDLE | __F_V },
717	[__ID_IBLINES] =	{ "iblines",	H_BOARD,	iblines,	__F_HANDLE | __F_LINES },
718	[__ID_IBLLO] =		{ "ibllo",	H_EITHER,	ibllo,		__F_HANDLE },
719	[__ID_IBLN] =		{ "ibln",	H_BOARD,	ibln,		__F_HANDLE | __F_PADVAL | __F_SADVAL | __F_LISTENFLAG },
720	[__ID_IBLOC] =		{ "ibloc",	H_EITHER,	ibloc,		__F_HANDLE },
721	[__ID_IBONL] =		{ "ibonl",	H_EITHER,	ibonl,		__F_HANDLE | __F_V },
722	[__ID_IBPAD] =		{ "ibpad",	H_EITHER,	ibpad,		__F_HANDLE | __F_PAD },
723	[__ID_IBPCT] =		{ "ibpct",	H_DEV,		ibpct,		__F_HANDLE },
724	[__ID_IBPOKE] =		{ "ibpoke",	H_EITHER,	ibpoke,		__F_HANDLE | __F_OPTION | __F_VALUE },
725	[__ID_IBPPC] =		{ "ibppc",	H_EITHER,	ibppc,		__F_HANDLE | __F_V },
726	[__ID_IBRD] =		{ "ibrd",	H_EITHER,	ibrd,		__F_HANDLE | __F_BUFFER | __F_CNT },
727	[__ID_IBRDA] =		{ "ibrda",	H_EITHER,	ibrda,		__F_HANDLE | __F_BUFFER | __F_CNT },
728	[__ID_IBRDF] =		{ "ibrdf",	H_EITHER,	ibrdf,		__F_HANDLE | __F_FLNAME },
729	[__ID_IBRDKEY] =	{ "ibrdkey",	H_EITHER,	ibrdkey,	__F_HANDLE | __F_BUFFER | __F_CNT },
730	[__ID_IBRPP] =		{ "ibrpp",	H_EITHER,	ibrpp,		__F_HANDLE | __F_PPR },
731	[__ID_IBRSC] =		{ "ibrsc",	H_BOARD,	ibrsc,		__F_HANDLE | __F_V },
732	[__ID_IBRSP] =		{ "ibrsp",	H_DEV,		ibrsp,		__F_HANDLE | __F_SPR },
733	[__ID_IBRSV] =		{ "ibrsv",	H_EITHER,	ibrsv,		__F_HANDLE | __F_V },
734	[__ID_IBSAD] =		{ "ibsad",	H_EITHER,	ibsad,		__F_HANDLE | __F_SAD },
735	[__ID_IBSGNL] =		{ "ibsgnl",	H_EITHER,	ibsgnl,		__F_HANDLE | __F_V },
736	[__ID_IBSIC] =		{ "ibsic",	H_BOARD,	ibsic,		__F_HANDLE },
737	[__ID_IBSRE] =		{ "ibsre",	H_BOARD,	ibsre,		__F_HANDLE | __F_V },
738	[__ID_IBSRQ] =		{ "ibsrq",	H_EITHER,	ibsrq,		__F_FUNC },
739	[__ID_IBSTOP] =		{ "ibstop",	H_EITHER,	ibstop,		__F_HANDLE },
740	[__ID_IBTMO] =		{ "ibtmo",	H_EITHER,	ibtmo,		__F_HANDLE | __F_TMO },
741	[__ID_IBTRAP] =		{ "ibtrap",	H_EITHER,	ibtrap,		__F_MASK | __F_MODE },
742	[__ID_IBTRG] =		{ "ibtrg",	H_DEV,		ibtrg,		__F_HANDLE },
743	[__ID_IBWAIT] =		{ "ibwait",	H_EITHER,	ibwait,		__F_HANDLE | __F_MASK },
744	[__ID_IBWRT] =		{ "ibwrt",	H_EITHER,	ibwrt,		__F_HANDLE | __F_BUFFER | __F_CNT },
745	[__ID_IBWRTA] =		{ "ibwrta",	H_EITHER,	ibwrta,		__F_HANDLE | __F_BUFFER | __F_CNT },
746	[__ID_IBWRTF] =		{ "ibwrtf",	H_EITHER,	ibwrtf,		__F_HANDLE | __F_FLNAME },
747	[__ID_IBWRTKEY] =	{ "ibwrtkey",	H_EITHER,	ibwrtkey,	__F_HANDLE | __F_BUFFER | __F_CNT },
748	[__ID_IBXTRC] =		{ "ibxtrc",	H_EITHER,	ibxtrc,		__F_HANDLE | __F_BUFFER | __F_CNT },
749};
750
751static const u_int max_ibhandler = sizeof ibhandlers / sizeof ibhandlers[0];
752
753static void
754ib_dump_args(struct ibhandler *ih, struct ibarg *ap)
755{
756
757	if (ih->name != NULL)
758		printf("%s(", ih->name);
759	else
760		printf("ibinvalid(");
761	printf("[0x%x]", ap->__field);
762	if (ap->__field & __F_HANDLE)	printf(" handle=%d", ap->handle);
763	if (ap->__field & __F_EOS)	printf(" eos=0x%x", ap->eos);
764	if (ap->__field & __F_EOT)	printf(" eot=%d", ap->eot);
765	if (ap->__field & __F_TMO)	printf(" tmo=%d", ap->tmo);
766	if (ap->__field & __F_PAD)	printf(" pad=0x%x", ap->pad);
767	if (ap->__field & __F_SAD)	printf(" sad=0x%x", ap->sad);
768	if (ap->__field & __F_BUFFER)	printf(" buffer=%p", ap->buffer);
769	if (ap->__field & __F_CNT)	printf(" cnt=%ld", ap->cnt);
770	if (ap->__field & __F_V)	printf(" v=%d/0x%x", ap->v, ap->v);
771	/* XXX more ... */
772	printf(")\n");
773}
774
775static int
776gpib_ib_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
777{
778	struct upd7210 *u;
779	struct ibfoo *ib;
780	int error = 0;
781
782	u = dev->si_drv1;
783
784	mtx_lock(&u->mutex);
785	if (u->busy) {
786		mtx_unlock(&u->mutex);
787		return (EBUSY);
788	}
789	u->busy = 1;
790	mtx_unlock(&u->mutex);
791
792	if (u->dmachan >= 0) {
793		mtx_lock(&Giant);
794		error = isa_dma_acquire(u->dmachan);
795		if (!error) {
796			error = isa_dma_init(u->dmachan, PAGE_SIZE, M_WAITOK);
797			if (error)
798				isa_dma_release(u->dmachan);
799		}
800		mtx_unlock(&Giant);
801	}
802
803	if (error) {
804		mtx_lock(&u->mutex);
805		u->busy = 0;
806		mtx_unlock(&u->mutex);
807		return (error);
808	}
809
810	ib = malloc(sizeof *ib, M_IBFOO, M_WAITOK | M_ZERO);
811	LIST_INIT(&ib->handles);
812	callout_init(&ib->callout, CALLOUT_MPSAFE);
813	ib->unrhdr = new_unrhdr(0, INT_MAX, NULL);
814	dev->si_drv2 = ib;
815	ib->u = u;
816	u->ibfoo = ib;
817	u->irq = gpib_ib_irq;
818
819	upd7210_wr(u, AUXMR, AUXMR_CRST);
820	DELAY(10000);
821	DELAY(1000);
822	upd7210_wr(u, IMR1, 0x00);
823	upd7210_wr(u, IMR2, 0x00);
824	upd7210_wr(u, SPMR, 0x00);
825	upd7210_wr(u, ADR, 0x00);
826	upd7210_wr(u, ADR, ADR_ARS | ADR_DL | ADR_DT);
827	upd7210_wr(u, ADMR, ADMR_ADM0 | ADMR_TRM0 | ADMR_TRM1);
828	upd7210_wr(u, EOSR, 0x00);
829	upd7210_wr(u, AUXMR, C_ICR | 8);
830	upd7210_wr(u, AUXMR, C_PPR | PPR_U);
831	upd7210_wr(u, AUXMR, C_AUXA);
832	upd7210_wr(u, AUXMR, C_AUXB + 3);
833	upd7210_wr(u, AUXMR, C_AUXE + 0);
834	upd7210_wr(u, AUXMR, AUXMR_PON);
835	upd7210_wr(u, AUXMR, AUXMR_CIFC);
836	DELAY(100);
837	upd7210_wr(u, AUXMR, AUXMR_SIFC);
838	upd7210_wr(u, AUXMR, AUXMR_SREN);
839	return (0);
840}
841
842static int
843gpib_ib_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
844{
845	struct upd7210 *u;
846	struct ibfoo *ib;
847
848	u = dev->si_drv1;
849	ib = dev->si_drv2;
850	/* XXX: assert pointer consistency */
851
852	u->ibfoo = NULL;
853	/* XXX: free handles */
854	dev->si_drv2 = NULL;
855	free(ib, M_IBFOO);
856
857	if (u->dmachan >= 0) {
858		mtx_lock(&Giant);
859		isa_dma_release(u->dmachan);
860		mtx_unlock(&Giant);
861	}
862	mtx_lock(&u->mutex);
863	u->busy = 0;
864	ibdebug = 0;
865	upd7210_wr(u, IMR1, 0x00);
866	upd7210_wr(u, IMR2, 0x00);
867	upd7210_wr(u, AUXMR, AUXMR_CRST);
868	DELAY(10000);
869	mtx_unlock(&u->mutex);
870	return (0);
871}
872
873static int
874gpib_ib_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
875{
876	struct ibarg *ap;
877	struct ibhandler *ih;
878	struct handle *h;
879	struct upd7210 *u;
880	struct ibfoo *ib;
881	int error;
882	struct timeval deadline, tv;
883
884	u = dev->si_drv1;
885	ib = u->ibfoo;
886
887	/* We only support a single ioctl, everything else is a mistake */
888	if (cmd != GPIB_IBFOO)
889		return (ENOIOCTL);
890
891	/* Check the identifier and field-bitmap in the arguments.  */
892	ap = (void *)data;
893	if (ap->__ident < 0 || ap->__ident >= max_ibhandler)
894		return (EINVAL);
895	ih = &ibhandlers[ap->__ident];
896	if (ap->__field != ih->args)
897		return (EINVAL);
898
899	if (ibdebug)
900		ib_dump_args(ih, ap);
901
902	if (ih->func == NULL)
903		return (EOPNOTSUPP);
904
905	ap->__iberr = 0;
906	ap->__ibsta = 0;
907	ap->__ibcnt = 0;
908	ap->retval = 0;
909
910	if (ap->__field & __F_TMO) {
911		if (ap->tmo < 0 || ap->tmo >= max_timeouts)
912			return (ib_set_error(ap, EARG));
913	}
914
915	if (ap->__field & __F_EOS) {
916		if ((ap->eos & ~(REOS | XEOS | BIN | 0xff)) ||
917		    ((ap->eos & (BIN | 0x80)) == 0x80))
918			return (ib_set_error(ap, EARG));
919	}
920	if (ap->__field & __F_PAD) {
921		if (ap->pad < 0 || ap->pad > 30)
922			return (ib_set_error(ap, EARG));
923	}
924	if (ap->__field & __F_SAD) {
925		if (ap->sad != 0 && (ap->sad < 0x60 || ap->sad > 126))
926			return (ib_set_error(ap, EARG));
927	}
928
929
930	mtx_lock(&u->mutex);
931
932
933	/* Find the handle, if any */
934	h = NULL;
935	if ((ap->__field & __F_HANDLE) && gethandle(u, ap, &h)) {
936		mtx_unlock(&u->mutex);
937		return (0);
938	}
939
940	/* Check that the handle is the right kind */
941	if (h != NULL && !(h->kind & ih->kind)) {
942		mtx_unlock(&u->mutex);
943		return (ib_set_error(ap, EARG));
944	}
945
946	/* Set up handle and deadline */
947	if (h != NULL && timevalisset(&h->timeout)) {
948		getmicrouptime(&deadline);
949		timevaladd(&deadline, &h->timeout);
950	} else {
951		timevalclear(&deadline);
952	}
953
954	/* Wait for the card to be(come) available, respect deadline */
955	while(u->busy != 1) {
956		error = msleep(ib, &u->mutex,
957		    PZERO | PCATCH, "gpib_ibioctl", hz / 10);
958		if (error == 0)
959			continue;
960		mtx_unlock(&u->mutex);
961		if (error == EINTR)
962			return(ib_set_error(ap, EABO));
963		if (error == EWOULDBLOCK && timevalisset(&deadline)) {
964			getmicrouptime(&tv);
965			if (timevalcmp(&deadline, &tv, <))
966				return(ib_had_timeout(ap));
967		}
968		mtx_lock(&u->mutex);
969	}
970	u->busy = 2;
971	mtx_unlock(&u->mutex);
972
973	/* Hand over deadline handling to the callout routine */
974	ib->ap = ap;
975	ib->h = h;
976	ib->mode = BUSY;
977	ib->deadline = deadline;
978	callout_reset(&ib->callout, hz / 5, gpib_ib_timeout, u);
979
980	error = ih->func(ib);
981
982	/* Release card */
983	ib->mode = IDLE;
984	ib->ap = NULL;
985	ib->h = NULL;
986	timevalclear(&deadline);
987	callout_stop(&ib->callout);
988
989	mtx_lock(&u->mutex);
990	u->busy = 1;
991	wakeup(ib);
992	mtx_unlock(&u->mutex);
993
994	if (error)
995		return(ib_set_errno(ap, error));
996	return (0);
997}
998
999struct cdevsw gpib_ib_cdevsw = {
1000	.d_version =	D_VERSION,
1001	.d_name =	"gpib_ib",
1002	.d_open	=	gpib_ib_open,
1003	.d_ioctl =	gpib_ib_ioctl,
1004	.d_close =	gpib_ib_close,
1005};
1006