ibfoo.c revision 141777
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 141777 2005-02-12 23:52:44Z phk $");
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 = IDLE;
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 / 100, 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_irq(u, 1);
367
368	gpib_ib_wait_xfer(u, ib);
369
370	mtx_unlock(&u->mutex);
371	return (len - ib->buflen);
372}
373
374static int
375pio_idata(struct upd7210 *u, u_char *data, int len)
376{
377	struct ibfoo *ib;
378
379	ib = u->ibfoo;
380
381	mtx_lock(&u->mutex);
382	ib->mode = PIO_IDATA;
383	ib->buf = data;
384	ib->buflen = len;
385	upd7210_wr(u, IMR1, IXR1_DI);
386
387	gpib_ib_wait_xfer(u, ib);
388
389	mtx_unlock(&u->mutex);
390	return (len - ib->buflen);
391}
392
393static int
394dma_idata(struct upd7210 *u, u_char *data, int len)
395{
396	int j;
397	struct ibfoo *ib;
398
399	KASSERT(u->dmachan >= 0, ("Bogus dmachan %d", u->dmachan));
400	ib = u->ibfoo;
401	ib->mode = DMA_IDATA;
402	mtx_lock(&Giant);
403	isa_dmastart(ISADMA_READ, data, len, u->dmachan);
404	mtx_unlock(&Giant);
405	mtx_lock(&u->mutex);
406	upd7210_wr(u, IMR1, IXR1_ENDRX);
407	upd7210_wr(u, IMR2, IMR2_DMAI);
408	gpib_ib_wait_xfer(u, ib);
409	mtx_unlock(&u->mutex);
410	mtx_lock(&Giant);
411	j = isa_dmastatus(u->dmachan);
412	isa_dmadone(ISADMA_READ, data, len, u->dmachan);
413	mtx_unlock(&Giant);
414	return (len - j);
415}
416
417static int
418ib_send_msg(struct ibfoo *ib, int msg)
419{
420	u_char buf[10];
421	int i, j;
422
423	i = 0;
424	buf[i++] = UNT;
425	buf[i++] = UNL;
426	buf[i++] = LAD | ib->h->pad;
427	if (ib->h->sad)
428		buf[i++] = LAD | TAD | ib->h->sad;
429	buf[i++] = TAD | 0;
430	buf[i++] = msg;
431	j = pio_cmd(ib->u, buf, i);
432	if (i != j)
433		ib_set_error(ib->ap, EABO); /* XXX ? */
434	return (0);
435}
436
437static int
438ibask(struct ibfoo *ib)
439{	/* XXX */
440
441	ibdebug = ib->ap->option;
442	return (0);
443}
444
445#define ibbna NULL
446#define ibcac NULL
447
448static int
449ibclr(struct ibfoo *ib)
450{
451
452	return (ib_send_msg(ib, SDC));
453}
454
455#define ibcmd NULL
456#define ibcmda NULL
457#define ibconfig NULL
458
459static int
460ibdev(struct ibfoo *ib)
461{	/* TBD */
462	struct handle *h;
463
464	h = malloc(sizeof *h, M_IBFOO, M_ZERO | M_WAITOK);
465	h->handle = alloc_unr(ib->unrhdr);
466	h->kind = H_DEV;
467	h->pad = ib->ap->pad;
468	h->sad = ib->ap->sad;
469	h->timeout = timeouts[ib->ap->tmo];
470	h->eot = ib->ap->eot;
471	h->eos = ib->ap->eos;
472	mtx_lock(&ib->u->mutex);
473	LIST_INSERT_HEAD(&ib->handles, h, list);
474	mtx_unlock(&ib->u->mutex);
475	ib->ap->__retval = h->handle;
476	return (0);
477}
478
479#define ibdiag NULL
480
481static int
482ibdma(struct ibfoo *ib)
483{
484
485	if (ib->u->dmachan < 0 && ib->ap->v)
486		return (ib_set_error(ib->ap, EARG));
487	ib->h->dma = ib->ap->v;
488	return (0);
489}
490
491static int
492ibeos(struct ibfoo *ib)
493{
494
495	ib->ap->__iberr = ib->h->eos;
496	ib->h->eos = ib->ap->eos;
497	if (ib->rdh == ib->h)
498		config_eos(ib->u, ib->h);
499	return (0);
500}
501
502static int
503ibeot(struct ibfoo *ib)
504{
505
506	ib->h->eot = ib->ap->eot;
507	return (0);
508}
509
510#define ibevent NULL
511#define ibfind NULL
512#define ibgts NULL
513#define ibist NULL
514#define iblines NULL
515#define ibllo NULL
516#define ibln NULL
517
518static int
519ibloc(struct ibfoo *ib)
520{	/* XXX */
521
522	if (ib->h->kind == H_BOARD)
523		return (EOPNOTSUPP); /* XXX */
524	return (ib_send_msg(ib, GTL));
525}
526
527static int
528ibonl(struct ibfoo *ib)
529{	/* XXX */
530
531	if (ib->ap->v)
532		return (EOPNOTSUPP);	/* XXX */
533	mtx_lock(&ib->u->mutex);
534	LIST_REMOVE(ib->h, list);
535	mtx_unlock(&ib->u->mutex);
536	free(ib->h, M_IBFOO);
537	ib->h = NULL;
538	return (0);
539}
540
541static int
542ibpad(struct ibfoo *ib)
543{
544
545	ib->h->pad = ib->ap->pad;
546	return (0);
547}
548
549#define ibpct NULL
550#define ibpoke NULL
551#define ibppc NULL
552
553static int
554ibrd(struct ibfoo *ib)
555{	/* TBD */
556	u_char buf[10], *bp;
557	int i, j, error, bl, bc;
558	u_char *dp;
559
560	if (ib->h->kind == H_BOARD)
561		return (EOPNOTSUPP); /* XXX */
562	bl = ib->ap->cnt;
563	if (bl > PAGE_SIZE)
564		bl = PAGE_SIZE;
565	bp = malloc(bl, M_IBFOO, M_WAITOK);
566
567	if (ib->rdh != ib->h) {
568		i = 0;
569		buf[i++] = UNT;
570		buf[i++] = UNL;
571		buf[i++] = LAD | 0;
572		buf[i++] = TAD | ib->h->pad;
573		if (ib->h->sad)
574			buf[i++] = ib->h->sad;
575		i = pio_cmd(ib->u, buf, i);
576		config_eos(ib->u, ib->h);
577		ib->rdh = ib->h;
578		ib->wrh = NULL;
579		upd7210_goto_standby(ib->u);
580	}
581	dp = ib->ap->buffer;
582	bc = ib->ap->cnt;
583	error = 0;
584	while (bc > 0 && ib->ap->__iberr == 0) {
585		j = imin(bc, PAGE_SIZE);
586		if (ib->h->dma)
587			i = dma_idata(ib->u, bp, j);
588		else
589			i = pio_idata(ib->u, bp, j);
590		error = copyout(bp, dp , i);
591		if (error)
592			break;
593		ib->ap->__ibcnt += i;
594		if (i != j)
595			break;
596		bc -= i;
597		dp += i;
598	}
599	free(bp, M_IBFOO);
600	return (error);
601}
602
603#define ibrda NULL
604#define ibrdf NULL
605#define ibrdkey NULL
606#define ibrpp NULL
607#define ibrsc NULL
608#define ibrsp NULL
609#define ibrsv NULL
610
611static int
612ibsad(struct ibfoo *ib)
613{
614
615	ib->h->sad = ib->ap->sad;
616	return (0);
617}
618
619#define ibsgnl NULL
620
621static int
622ibsic(struct ibfoo *ib)
623{	/* TBD */
624
625	upd7210_wr(ib->u, AUXMR, AUXMR_SIFC);
626	DELAY(100);
627	upd7210_wr(ib->u, AUXMR, AUXMR_CIFC);
628	return (0);
629}
630
631#define ibsre NULL
632#define ibsrq NULL
633#define ibstop NULL
634
635static int
636ibtmo(struct ibfoo *ib)
637{
638
639	ib->h->timeout = timeouts[ib->ap->tmo];
640	return (0);
641}
642
643#define ibtrap NULL
644
645static int
646ibtrg(struct ibfoo *ib)
647{
648
649	return (ib_send_msg(ib, GET));
650}
651
652#define ibwait NULL
653
654static int
655ibwrt(struct ibfoo *ib)
656{	/* XXX */
657	u_char buf[10], *bp;
658	int i;
659
660	if (ib->h->kind == H_BOARD)
661		return (EOPNOTSUPP);
662	bp = malloc(ib->ap->cnt, M_IBFOO, M_WAITOK);
663	/* XXX: bigger than PAGE_SIZE handling */
664	i = copyin(ib->ap->buffer, bp, ib->ap->cnt);
665	if (i) {
666		free(bp, M_IBFOO);
667		return (i);
668	}
669	if (ib->wrh != ib->h) {
670		i = 0;
671		buf[i++] = UNT;
672		buf[i++] = UNL;
673		buf[i++] = LAD | ib->h->pad;
674		if (ib->h->sad)
675			buf[i++] = LAD | TAD | ib->h->sad;
676		buf[i++] = TAD | 0;
677		i = pio_cmd(ib->u, buf, i);
678		ib->rdh = NULL;
679		ib->wrh = ib->h;
680		upd7210_goto_standby(ib->u);
681		config_eos(ib->u, ib->h);
682	}
683	ib->doeoi = ib->h->eot;
684	i = pio_odata(ib->u, bp, ib->ap->cnt);
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, 1);
813	ib->unrhdr = new_unrhdr(0, INT_MAX);
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 / 100, 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