ibfoo.c revision 141768
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 141768 2005-02-12 21:07:09Z 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
64struct handle {
65	LIST_ENTRY(handle)	list;
66	int			handle;
67	int			pad;
68	int			sad;
69	struct timeval		timeout;
70	int			eot;
71	int			eos;
72	int			dma;
73};
74
75struct ibfoo {
76	struct upd7210		*u;
77	LIST_HEAD(,handle)	handles;
78	struct unrhdr		*unrhdr;
79	struct callout		callout;
80	struct handle		*h;
81	struct ibarg		*ap;
82
83	enum {
84		IDLE,
85		BUSY,
86		PIO_IDATA,
87		PIO_ODATA,
88		PIO_CMD,
89		DMA_IDATA
90	}			mode;
91
92	struct timeval		deadline;
93
94	struct handle		*rdh;		/* addressed for read */
95	struct handle		*wrh;		/* addressed for write */
96
97	int		 	doeoi;
98
99	u_char			*buf;
100	u_int			buflen;
101};
102
103typedef int ibhandler_t(struct ibfoo *ib);
104
105static struct timeval timeouts[] = {
106	[TNONE] =	{    0,      0},
107	[T10us] =	{    0,     10},
108	[T30us] =	{    0,     30},
109	[T100us] =	{    0,    100},
110	[T300us] =	{    0,    300},
111	[T1ms] =	{    0,   1000},
112	[T3ms] =	{    0,   3000},
113	[T10ms] =	{    0,  10000},
114	[T30ms] =	{    0,  30000},
115	[T100ms] =	{    0, 100000},
116	[T300ms] =	{    0, 300000},
117	[T1s] =		{    1,      0},
118	[T3s] =		{    3,      0},
119	[T10s] =	{   10,      0},
120	[T30s] =	{   30,      0},
121	[T100s] =	{  100,      0},
122	[T300s] =	{  300,      0},
123	[T1000s] =	{ 1000,      0}
124};
125
126static const u_int max_timeouts = sizeof timeouts / sizeof timeouts[0];
127
128static int ibdebug;
129
130static int
131ib_set_error(struct ibarg *ap, int error)
132{
133
134	if (ap->__iberr == 0)
135		ap->__iberr = error;
136	ap->__ibsta |= ERR;
137	ap->__retval = ap->__ibsta;
138	return (0);
139}
140
141static int
142ib_had_timeout(struct ibarg *ap)
143{
144
145	ib_set_error(ap, EABO);
146	ap->__ibsta |= TIMO;
147	ap->__retval = ap->__ibsta;
148	return (0);
149}
150
151static int
152ib_set_errno(struct ibarg *ap, int errno)
153{
154
155	if (ap->__iberr == 0) {
156		ap->__iberr = EDVR;
157		ap->__ibcnt = errno;
158	}
159	ap->__ibsta |= ERR;
160	ap->__retval = ap->__ibsta;
161	return (0);
162}
163
164static int
165gpib_ib_irq(struct upd7210 *u, int intr __unused)
166{
167	struct ibfoo *ib;
168
169	ib = u->ibfoo;
170
171	mtx_assert(&u->mutex, MA_OWNED);
172	switch (ib->mode) {
173	case PIO_CMD:
174		if (!(u->rreg[ISR2] & IXR2_CO))
175			return (0);
176		if (ib->buflen == 0)
177			break;
178		upd7210_wr(u, CDOR, *ib->buf);
179		ib->buf++;
180		ib->buflen--;
181		return (1);
182	case PIO_IDATA:
183		if (!(u->rreg[ISR1] & IXR1_DI))
184			return (0);
185		*ib->buf = upd7210_rd(u, DIR);
186		ib->buf++;
187		ib->buflen--;
188		if (ib->buflen == 0 || (u->rreg[ISR1] & IXR1_ENDRX))
189			break;
190		return (1);
191	case PIO_ODATA:
192		if (!(u->rreg[ISR1] & IXR1_DO))
193			return (0);
194		if (ib->buflen == 0)
195			break;
196		if (ib->buflen == 1 && ib->doeoi)
197			upd7210_wr(u, AUXMR, AUXMR_SEOI);
198		upd7210_wr(u, CDOR, *ib->buf);
199		ib->buf++;
200		ib->buflen--;
201		return (1);
202	case DMA_IDATA:
203		if (!(u->rreg[ISR1] & IXR1_ENDRX))
204			return (0);
205		break;
206	default:
207		return (0);
208	}
209	upd7210_wr(u, IMR1, 0);
210	upd7210_wr(u, IMR2, 0);
211	ib->mode = BUSY;
212	wakeup(&ib->buflen);
213	return (1);
214}
215
216static void
217gpib_ib_timeout(void *arg)
218{
219	struct upd7210 *u;
220	struct ibfoo *ib;
221	struct timeval tv;
222
223	u = arg;
224	ib = u->ibfoo;
225	mtx_lock(&u->mutex);
226	if (ib->mode == DMA_IDATA && isa_dmatc(u->dmachan)) {
227		upd7210_wr(u, IMR1, 0);
228		upd7210_wr(u, IMR2, 0);
229		ib->mode = IDLE;
230		wakeup(&ib->buflen);
231	}
232	if (ib->mode > BUSY) {
233		upd7210_rd(u, ISR1);
234		upd7210_rd(u, ISR2);
235		gpib_ib_irq(u, 2);
236	}
237	if (ib->mode != IDLE && timevalisset(&ib->deadline)) {
238		getmicrouptime(&tv);
239		if (timevalcmp(&ib->deadline, &tv, <)) {
240			ib_had_timeout(ib->ap);
241			upd7210_wr(u, IMR1, 0);
242			upd7210_wr(u, IMR2, 0);
243			ib->mode = BUSY;
244			wakeup(&ib->buflen);
245		}
246	}
247	if (ib->mode != IDLE)
248		callout_reset(&ib->callout, hz / 100, gpib_ib_timeout, arg);
249	mtx_unlock(&u->mutex);
250}
251
252static void
253gpib_ib_wait_xfer(struct upd7210 *u, struct ibfoo *ib)
254{
255	int i;
256
257	mtx_assert(&u->mutex, MA_OWNED);
258	while (ib->mode > BUSY) {
259		i = msleep(&ib->buflen, &u->mutex,
260		    PZERO | PCATCH, "ibwxfr", 0);
261		if (i == EINTR) {
262			ib_set_errno(ib->ap, i);
263			break;
264		}
265		if (u->rreg[ISR1] & IXR1_ERR) {
266			ib_set_error(ib->ap, EABO);	/* XXX ? */
267			break;
268		}
269	}
270	ib->mode = BUSY;
271	ib->buf = NULL;
272	upd7210_wr(u, IMR1, 0);
273	upd7210_wr(u, IMR2, 0);
274}
275
276static void
277config_eos(struct upd7210 *u, struct handle *h)
278{
279	int i;
280
281	i = 0;
282	if (h->eos & REOS) {
283		upd7210_wr(u, EOSR, h->eos & 0xff);
284		i |= AUXA_REOS;
285	}
286	if (h->eos & XEOS) {
287		upd7210_wr(u, EOSR, h->eos & 0xff);
288		i |= AUXA_XEOS;
289	}
290	if (h->eos & BIN)
291		i |= AUXA_BIN;
292	upd7210_wr(u, AUXRA, C_AUXA | i);
293}
294
295/*
296 * Look up the handle, and set the deadline if the handle has a timeout.
297 */
298static int
299gethandle(struct upd7210 *u, struct ibarg *ap, struct handle **hp)
300{
301	struct ibfoo *ib;
302	struct handle *h;
303
304	KASSERT(ap->__field & __F_HANDLE, ("gethandle without __F_HANDLE"));
305	ib = u->ibfoo;
306	LIST_FOREACH(h, &ib->handles, list) {
307		if (h->handle == ap->handle) {
308			*hp = h;
309			return (0);
310		}
311	}
312	ib_set_error(ap, EARG);
313	return (1);
314}
315
316static int
317pio_cmd(struct upd7210 *u, u_char *cmd, int len)
318{
319	struct ibfoo *ib;
320
321	ib = u->ibfoo;
322
323	if (ib->rdh != NULL || ib->wrh != NULL) {
324		upd7210_take_ctrl_async(u);
325		ib->rdh = NULL;
326		ib->wrh = NULL;
327	}
328	mtx_lock(&u->mutex);
329	ib->mode = PIO_CMD;
330	ib->buf = cmd;
331	ib->buflen = len;
332	upd7210_wr(u, IMR2, IXR2_CO);
333
334	gpib_ib_irq(u, 1);
335
336	gpib_ib_wait_xfer(u, ib);
337
338	mtx_unlock(&u->mutex);
339	return (len - ib->buflen);
340}
341
342static int
343pio_odata(struct upd7210 *u, u_char *data, int len)
344{
345	struct ibfoo *ib;
346
347	ib = u->ibfoo;
348
349	if (len == 0)
350		return (0);
351	mtx_lock(&u->mutex);
352	ib->mode = PIO_ODATA;
353	ib->buf = data;
354	ib->buflen = len;
355	upd7210_wr(u, IMR1, IXR1_DO);
356
357	gpib_ib_irq(u, 1);
358
359	gpib_ib_wait_xfer(u, ib);
360
361	mtx_unlock(&u->mutex);
362	return (len - ib->buflen);
363}
364
365static int
366pio_idata(struct upd7210 *u, u_char *data, int len)
367{
368	struct ibfoo *ib;
369
370	ib = u->ibfoo;
371
372	mtx_lock(&u->mutex);
373	ib->mode = PIO_IDATA;
374	ib->buf = data;
375	ib->buflen = len;
376	upd7210_wr(u, IMR1, IXR1_DI);
377
378	gpib_ib_wait_xfer(u, ib);
379
380	mtx_unlock(&u->mutex);
381	return (len - ib->buflen);
382}
383
384static int
385dma_idata(struct upd7210 *u, u_char *data, int len)
386{
387	int j;
388	struct ibfoo *ib;
389
390	ib = u->ibfoo;
391	ib->mode = DMA_IDATA;
392	mtx_lock(&Giant);
393	isa_dmastart(ISADMA_READ, data, len, u->dmachan);
394	mtx_unlock(&Giant);
395	mtx_lock(&u->mutex);
396	upd7210_wr(u, IMR1, IXR1_ENDRX);
397	upd7210_wr(u, IMR2, IMR2_DMAI);
398	gpib_ib_wait_xfer(u, ib);
399	mtx_unlock(&u->mutex);
400	mtx_lock(&Giant);
401	j = isa_dmastatus(u->dmachan);
402	isa_dmadone(ISADMA_READ, data, len, u->dmachan);
403	mtx_unlock(&Giant);
404	return (len - j);
405}
406
407#define ibask NULL
408#define ibbna NULL
409#define ibcac NULL
410#define ibclr NULL
411#define ibcmd NULL
412#define ibcmda NULL
413#define ibconfig NULL
414
415static int
416ibdev(struct ibfoo *ib)
417{
418	struct handle *h;
419
420	h = malloc(sizeof *h, M_IBFOO, M_ZERO | M_WAITOK);
421	h->handle = alloc_unr(ib->unrhdr);
422	h->pad = ib->ap->pad;
423	h->sad = ib->ap->sad;
424	h->timeout = timeouts[ib->ap->tmo];
425	h->eot = ib->ap->eot;
426	h->eos = ib->ap->eos;
427	mtx_lock(&ib->u->mutex);
428	LIST_INSERT_HEAD(&ib->handles, h, list);
429	mtx_unlock(&ib->u->mutex);
430	ib->ap->__retval = h->handle;
431	return (0);
432}
433
434#define ibdiag NULL
435
436static int
437ibdma(struct ibfoo *ib)
438{
439
440	ib->h->dma = ib->ap->v;
441	return (0);
442}
443
444static int
445ibeos(struct ibfoo *ib)
446{
447
448	ib->h->eos = ib->ap->eos;
449	if (ib->rdh == ib->h)
450		config_eos(ib->u, ib->h);
451	return (0);
452}
453
454static int
455ibeot(struct ibfoo *ib)
456{
457
458	ib->h->eot = ib->ap->eot;
459	return (0);
460}
461
462#define ibevent NULL
463#define ibfind NULL
464#define ibgts NULL
465#define ibist NULL
466#define iblines NULL
467#define ibllo NULL
468#define ibln NULL
469#define ibloc NULL
470#define ibonl NULL
471#define ibpad NULL
472#define ibpct NULL
473#define ibpoke NULL
474#define ibppc NULL
475
476static int
477ibrd(struct ibfoo *ib)
478{
479	u_char buf[10], *bp;
480	int i, j, error, bl, bc;
481	u_char *dp;
482
483	bl = ib->ap->cnt;
484	if (bl > PAGE_SIZE)
485		bl = PAGE_SIZE;
486	bp = malloc(bl, M_IBFOO, M_WAITOK);
487
488	if (ib->rdh != ib->h) {
489		i = 0;
490		buf[i++] = UNT;
491		buf[i++] = UNL;
492		buf[i++] = LAD | 0;
493		buf[i++] = TAD | ib->h->pad;
494		if (ib->h->sad)
495			buf[i++] = ib->h->sad;
496		i = pio_cmd(ib->u, buf, i);
497		config_eos(ib->u, ib->h);
498		ib->rdh = ib->h;
499		ib->wrh = NULL;
500		upd7210_goto_standby(ib->u);
501	}
502	dp = ib->ap->buffer;
503	bc = ib->ap->cnt;
504	error = 0;
505	while (bc > 0 && ib->ap->__iberr == 0) {
506		j = imin(bc, PAGE_SIZE);
507		if (ib->h->dma)
508			i = dma_idata(ib->u, bp, j);
509		else
510			i = pio_idata(ib->u, bp, j);
511		if (i <= 0)
512			break;
513		error = copyout(bp, dp , i);
514		if (error)
515			break;
516		ib->ap->__ibcnt += i;
517		if (i != j)
518			break;
519		bc -= i;
520		dp += i;
521	}
522	free(bp, M_IBFOO);
523	return (error);
524}
525
526#define ibrda NULL
527#define ibrdf NULL
528#define ibrdkey NULL
529#define ibrpp NULL
530#define ibrsc NULL
531#define ibrsp NULL
532#define ibrsv NULL
533#define ibsad NULL
534#define ibsgnl NULL
535#define ibsic NULL
536#define ibsre NULL
537#define ibsrq NULL
538#define ibstop NULL
539
540static int
541ibtmo(struct ibfoo *ib)
542{
543
544	ib->h->timeout = timeouts[ib->ap->tmo];
545	return (0);
546}
547
548#define ibtrap NULL
549#define ibtrg NULL
550#define ibwait NULL
551
552static int
553ibwrt(struct ibfoo *ib)
554{
555	u_char buf[10], *bp;
556	int i;
557
558	bp = malloc(ib->ap->cnt, M_IBFOO, M_WAITOK);
559	/* XXX: bigger than PAGE_SIZE handling */
560	i = copyin(ib->ap->buffer, bp, ib->ap->cnt);
561	if (i) {
562		free(bp, M_IBFOO);
563		return (i);
564	}
565	if (ib->wrh != ib->h) {
566		i = 0;
567		buf[i++] = UNT;
568		buf[i++] = UNL;
569		buf[i++] = LAD | ib->h->pad;
570		if (ib->h->sad)
571			buf[i++] = LAD | TAD | ib->h->sad;
572		buf[i++] = TAD | 0;
573		i = pio_cmd(ib->u, buf, i);
574		ib->rdh = NULL;
575		ib->wrh = ib->h;
576		upd7210_goto_standby(ib->u);
577		config_eos(ib->u, ib->h);
578	}
579	ib->doeoi = ib->h->eot;
580	i = pio_odata(ib->u, bp, ib->ap->cnt);
581	ib->ap->__ibcnt = i;
582	free(bp, M_IBFOO);
583	return (0);
584}
585
586#define ibwrta NULL
587#define ibwrtf NULL
588#define ibwrtkey NULL
589#define ibxtrc NULL
590
591static struct ibhandler {
592	const char 	*name;
593	ibhandler_t	*func;
594	u_int		args;
595} ibhandlers[] = {
596	[__ID_IBASK] =		{ "ibask",	ibask,		__F_HANDLE | __F_OPTION | __F_RETVAL },
597	[__ID_IBBNA] =		{ "ibbna",	ibbna,		__F_HANDLE | __F_BDNAME },
598	[__ID_IBCAC] =		{ "ibcac",	ibcac,		__F_HANDLE | __F_V },
599	[__ID_IBCLR] =		{ "ibclr",	ibclr,		__F_HANDLE },
600	[__ID_IBCMDA] =		{ "ibcmda",	ibcmda,		__F_HANDLE | __F_BUFFER | __F_CNT },
601	[__ID_IBCMD] =		{ "ibcmd",	ibcmd,		__F_HANDLE | __F_BUFFER | __F_CNT },
602	[__ID_IBCONFIG] =	{ "ibconfig",	ibconfig,	__F_HANDLE | __F_OPTION | __F_VALUE },
603	[__ID_IBDEV] =		{ "ibdev",	ibdev,		__F_BOARDID | __F_PAD | __F_SAD | __F_TMO | __F_EOT | __F_EOS },
604	[__ID_IBDIAG] =		{ "ibdiag",	ibdiag,		__F_HANDLE | __F_BUFFER | __F_CNT },
605	[__ID_IBDMA] =		{ "ibdma",	ibdma,		__F_HANDLE | __F_V },
606	[__ID_IBEOS] =		{ "ibeos",	ibeos,		__F_HANDLE | __F_EOS },
607	[__ID_IBEOT] =		{ "ibeot",	ibeot,		__F_HANDLE | __F_EOT },
608	[__ID_IBEVENT] =	{ "ibevent",	ibevent,	__F_HANDLE | __F_EVENT },
609	[__ID_IBFIND] =		{ "ibfind",	ibfind,		__F_BDNAME },
610	[__ID_IBGTS] =		{ "ibgts",	ibgts,		__F_HANDLE | __F_V },
611	[__ID_IBIST] =		{ "ibist",	ibist,		__F_HANDLE | __F_V },
612	[__ID_IBLINES] =	{ "iblines",	iblines,	__F_HANDLE | __F_LINES },
613	[__ID_IBLLO] =		{ "ibllo",	ibllo,		__F_HANDLE },
614	[__ID_IBLN] =		{ "ibln",	ibln,		__F_HANDLE | __F_PADVAL | __F_SADVAL | __F_LISTENFLAG },
615	[__ID_IBLOC] =		{ "ibloc",	ibloc,		__F_HANDLE },
616	[__ID_IBONL] =		{ "ibonl",	ibonl,		__F_HANDLE | __F_V },
617	[__ID_IBPAD] =		{ "ibpad",	ibpad,		__F_HANDLE | __F_V },
618	[__ID_IBPCT] =		{ "ibpct",	ibpct,		__F_HANDLE },
619	[__ID_IBPOKE] =		{ "ibpoke",	ibpoke,		__F_HANDLE | __F_OPTION | __F_VALUE },
620	[__ID_IBPPC] =		{ "ibppc",	ibppc,		__F_HANDLE | __F_V },
621	[__ID_IBRDA] =		{ "ibrda",	ibrda,		__F_HANDLE | __F_BUFFER | __F_CNT },
622	[__ID_IBRDF] =		{ "ibrdf",	ibrdf,		__F_HANDLE | __F_FLNAME },
623	[__ID_IBRDKEY] =	{ "ibrdkey",	ibrdkey,	__F_HANDLE | __F_BUFFER | __F_CNT },
624	[__ID_IBRD] =		{ "ibrd",	ibrd,		__F_HANDLE | __F_BUFFER | __F_CNT },
625	[__ID_IBRPP] =		{ "ibrpp",	ibrpp,		__F_HANDLE | __F_PPR },
626	[__ID_IBRSC] =		{ "ibrsc",	ibrsc,		__F_HANDLE | __F_V },
627	[__ID_IBRSP] =		{ "ibrsp",	ibrsp,		__F_HANDLE | __F_SPR },
628	[__ID_IBRSV] =		{ "ibrsv",	ibrsv,		__F_HANDLE | __F_V },
629	[__ID_IBSAD] =		{ "ibsad",	ibsad,		__F_HANDLE | __F_V },
630	[__ID_IBSGNL] =		{ "ibsgnl",	ibsgnl,		__F_HANDLE | __F_V },
631	[__ID_IBSIC] =		{ "ibsic",	ibsic,		__F_HANDLE },
632	[__ID_IBSRE] =		{ "ibsre",	ibsre,		__F_HANDLE | __F_V },
633	[__ID_IBSRQ] =		{ "ibsrq",	ibsrq,		__F_FUNC },
634	[__ID_IBSTOP] =		{ "ibstop",	ibstop,		__F_HANDLE },
635	[__ID_IBTMO] =		{ "ibtmo",	ibtmo,		__F_HANDLE | __F_TMO },
636	[__ID_IBTRAP] =		{ "ibtrap",	ibtrap,		__F_MASK | __F_MODE },
637	[__ID_IBTRG] =		{ "ibtrg",	ibtrg,		__F_HANDLE },
638	[__ID_IBWAIT] =		{ "ibwait",	ibwait,		__F_HANDLE | __F_MASK },
639	[__ID_IBWRTA] =		{ "ibwrta",	ibwrta,		__F_HANDLE | __F_BUFFER | __F_CNT },
640	[__ID_IBWRTF] =		{ "ibwrtf",	ibwrtf,		__F_HANDLE | __F_FLNAME },
641	[__ID_IBWRTKEY] =	{ "ibwrtkey",	ibwrtkey,	__F_HANDLE | __F_BUFFER | __F_CNT },
642	[__ID_IBWRT] =		{ "ibwrt",	ibwrt,		__F_HANDLE | __F_BUFFER | __F_CNT },
643	[__ID_IBXTRC] =		{ "ibxtrc",	ibxtrc,		__F_HANDLE | __F_BUFFER | __F_CNT },
644};
645
646static const u_int max_ibhandler = sizeof ibhandlers / sizeof ibhandlers[0];
647
648static void
649ib_dump_args(struct ibhandler *ih, struct ibarg *ap)
650{
651
652	if (ih->name != NULL)
653		printf("%s(", ih->name);
654	else
655		printf("ibinvalid(");
656	printf("[0x%x]", ap->__field);
657	if (ap->__field & __F_HANDLE)	printf(" handle=%d", ap->handle);
658	if (ap->__field & __F_EOS)	printf(" eos=%d", ap->eos);
659	if (ap->__field & __F_EOT)	printf(" eot=%d", ap->eot);
660	if (ap->__field & __F_TMO)	printf(" tmo=%d", ap->tmo);
661	if (ap->__field & __F_PAD)	printf(" pad=%d", ap->pad);
662	if (ap->__field & __F_SAD)	printf(" sad=%d", ap->sad);
663	if (ap->__field & __F_BUFFER)	printf(" buffer=%p", ap->buffer);
664	if (ap->__field & __F_CNT)	printf(" cnt=%ld", ap->cnt);
665	/* XXX more ... */
666	printf(")\n");
667}
668
669static int
670gpib_ib_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
671{
672	struct upd7210 *u;
673	struct ibfoo *ib;
674	int error;
675
676	u = dev->si_drv1;
677
678	mtx_lock(&u->mutex);
679	if (u->busy) {
680		mtx_unlock(&u->mutex);
681		return (EBUSY);
682	}
683	u->busy = 1;
684	mtx_unlock(&u->mutex);
685
686	mtx_lock(&Giant);
687	error = isa_dma_acquire(u->dmachan);
688	if (!error) {
689		error = isa_dma_init(u->dmachan, PAGE_SIZE, M_WAITOK);
690		if (error)
691			isa_dma_release(u->dmachan);
692	}
693	mtx_unlock(&Giant);
694	if (error) {
695		mtx_lock(&u->mutex);
696		u->busy = 0;
697		mtx_unlock(&u->mutex);
698		return (error);
699	}
700
701	ib = malloc(sizeof *ib, M_IBFOO, M_WAITOK | M_ZERO);
702	LIST_INIT(&ib->handles);
703	callout_init(&ib->callout, 1);
704	ib->unrhdr = new_unrhdr(0, INT_MAX);
705	dev->si_drv2 = ib;
706	ib->u = u;
707	u->ibfoo = ib;
708	u->irq = gpib_ib_irq;
709
710	upd7210_wr(u, AUXMR, AUXMR_CRST);
711	DELAY(10000);
712	DELAY(1000);
713	upd7210_wr(u, IMR1, 0x00);
714	upd7210_wr(u, IMR2, 0x00);
715	upd7210_wr(u, SPMR, 0x00);
716	upd7210_wr(u, ADR, 0x00);
717	upd7210_wr(u, ADR, ADR_ARS | ADR_DL | ADR_DT);
718	upd7210_wr(u, ADMR, ADMR_ADM0 | ADMR_TRM0 | ADMR_TRM1);
719	upd7210_wr(u, EOSR, 0x00);
720	upd7210_wr(u, AUXMR, C_ICR | 8);
721	upd7210_wr(u, AUXMR, C_PPR | PPR_U);
722	upd7210_wr(u, AUXMR, C_AUXA);
723	upd7210_wr(u, AUXMR, C_AUXB + 3);
724	upd7210_wr(u, AUXMR, C_AUXE + 0);
725	upd7210_wr(u, AUXMR, AUXMR_PON);
726	upd7210_wr(u, AUXMR, AUXMR_CIFC);
727	DELAY(100);
728	upd7210_wr(u, AUXMR, AUXMR_SIFC);
729	upd7210_wr(u, AUXMR, AUXMR_SREN);
730	return (0);
731}
732
733static int
734gpib_ib_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
735{
736	struct upd7210 *u;
737	struct ibfoo *ib;
738
739	u = dev->si_drv1;
740	ib = dev->si_drv2;
741	/* XXX: assert pointer consistency */
742
743	u->ibfoo = NULL;
744	/* XXX: free handles */
745	dev->si_drv2 = NULL;
746	free(ib, M_IBFOO);
747
748	mtx_lock(&Giant);
749	isa_dma_release(u->dmachan);
750	mtx_unlock(&Giant);
751	mtx_lock(&u->mutex);
752	u->busy = 0;
753	upd7210_wr(u, IMR1, 0x00);
754	upd7210_wr(u, IMR2, 0x00);
755	upd7210_wr(u, AUXMR, AUXMR_CRST);
756	DELAY(10000);
757	mtx_unlock(&u->mutex);
758	return (0);
759}
760
761static int
762gpib_ib_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
763{
764	struct ibarg *ap;
765	struct ibhandler *ih;
766	struct handle *h;
767	struct upd7210 *u;
768	struct ibfoo *ib;
769	int error;
770	struct timeval deadline, tv;
771
772	u = dev->si_drv1;
773	ib = u->ibfoo;
774
775	/* We only support a single ioctl, everything else is a mistake */
776	if (cmd != GPIB_IBFOO)
777		return (ENOIOCTL);
778
779	/* Check the identifier and field-bitmap in the arguments.  */
780	ap = (void *)data;
781	if (ap->__ident < 0 || ap->__ident >= max_ibhandler)
782		return (EINVAL);
783	ih = &ibhandlers[ap->__ident];
784	if (ap->__field != ih->args)
785		return (EINVAL);
786
787	if (ibdebug)
788		ib_dump_args(ih, ap);
789
790	if (ih->func == NULL)
791		return (EOPNOTSUPP);
792
793	ap->__iberr = 0;
794	ap->__ibsta = 0;
795	ap->__ibcnt = 0;
796	ap->retval = 0;
797
798	if (ap->__field & __F_TMO) {
799		if (ap->tmo < 0 || ap->tmo >= max_timeouts)
800			return (ib_set_error(ap, EARG));
801	}
802
803	if (ap->__field & __F_EOS) {
804		if ((ap->eos & ~(REOS | XEOS | BIN | 0xff)) ||
805		    ((ap->eos & (BIN | 0x80)) == 0x80))
806			return (ib_set_error(ap, EARG));
807	}
808	if (ap->__field & __F_PAD) {
809		if (ap->pad < 0 || ap->pad > 30)
810			return (ib_set_error(ap, EARG));
811	}
812	if (ap->__field & __F_SAD) {
813		if (ap->sad != 0 && (ap->sad < 0x60 || ap->sad > 126))
814			return (ib_set_error(ap, EARG));
815	}
816
817
818	mtx_lock(&u->mutex);
819
820
821	/* Find the handle, if any */
822	h = NULL;
823	if ((ap->__field & __F_HANDLE) && gethandle(u, ap, &h)) {
824		mtx_unlock(&u->mutex);
825		return (0);
826	}
827
828	/* Set up handle and deadline */
829	if (h != NULL && timevalisset(&h->timeout)) {
830		getmicrouptime(&deadline);
831		timevaladd(&deadline, &h->timeout);
832	} else {
833		timevalclear(&deadline);
834	}
835
836	/* Wait for the card to be(come) available, respect deadline */
837	while(u->busy != 1) {
838		error = msleep(ib, &u->mutex,
839		    PZERO | PCATCH, "gpib_ibioctl", hz / 10);
840		if (error == 0)
841			continue;
842		mtx_unlock(&u->mutex);
843		if (error == EINTR)
844			return(ib_set_error(ap, EABO));
845		if (error == EWOULDBLOCK && timevalisset(&deadline)) {
846			getmicrouptime(&tv);
847			if (timevalcmp(&deadline, &tv, <))
848				return(ib_had_timeout(ap));
849		}
850		mtx_lock(&u->mutex);
851	}
852	u->busy = 2;
853	mtx_unlock(&u->mutex);
854
855	/* Hand over deadline handling to the callout routine */
856	ib->ap = ap;
857	ib->h = h;
858	ib->mode = BUSY;
859	ib->deadline = deadline;
860	callout_reset(&ib->callout, hz / 100, gpib_ib_timeout, u);
861
862	error = ih->func(ib);
863
864	/* Release card */
865	ib->mode = IDLE;
866	ib->ap = NULL;
867	ib->h = NULL;
868	timevalclear(&deadline);
869	callout_stop(&ib->callout);
870
871	mtx_lock(&u->mutex);
872	u->busy = 1;
873	wakeup(ib);
874	mtx_unlock(&u->mutex);
875
876	if (error)
877		return(ib_set_errno(ap, error));
878	return (0);
879}
880
881struct cdevsw gpib_ib_cdevsw = {
882	.d_version =	D_VERSION,
883	.d_name =	"gpib_ib",
884	.d_open	=	gpib_ib_open,
885	.d_ioctl =	gpib_ib_ioctl,
886	.d_close =	gpib_ib_close,
887};
888