xref: /netbsd-src/sys/dev/gpib/gpib.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: gpib.c,v 1.2 2004/09/13 12:55:47 drochner Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Gregory McGarry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: gpib.c,v 1.2 2004/09/13 12:55:47 drochner Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/conf.h>
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #include <sys/malloc.h>
48 #include <sys/proc.h>
49 
50 #include <dev/gpib/gpibvar.h>
51 
52 #include <dev/gpib/gpibio.h>		/* XXX */
53 
54 #include "locators.h"
55 
56 #define DEBUG
57 
58 #ifdef DEBUG
59 int gpibdebug = 0xff;
60 #define DBG_FOLLOW	0x01
61 #define DBG_INTR	0x02
62 #define DBG_FAIL	0x04
63 #define DPRINTF(mask, str)	if (gpibdebug & (mask)) printf str
64 #else
65 #define DPRINTF(mask, str)	/* nothing */
66 #endif
67 
68 int	gpibmatch __P((struct device *, struct cfdata *, void *));
69 void	gpibattach __P((struct device *, struct device *, void *));
70 
71 CFATTACH_DECL(gpib, sizeof(struct gpib_softc),
72 	gpibmatch, gpibattach, NULL, NULL);
73 
74 static int	gpibsubmatch1(struct device *, struct cfdata *,
75 			      const locdesc_t *, void *);
76 static int	gpibsubmatch2(struct device *, struct cfdata *,
77 			      const locdesc_t *, void *);
78 static int	gpibprint(void *, const char *);
79 
80 dev_type_open(gpibopen);
81 dev_type_close(gpibclose);
82 dev_type_read(gpibread);
83 dev_type_write(gpibwrite);
84 dev_type_ioctl(gpibioctl);
85 dev_type_poll(gpibpoll);
86 
87 const struct cdevsw gpib_cdevsw = {
88 	gpibopen, gpibclose, gpibread, gpibwrite, gpibioctl,
89 	nostop, notty, gpibpoll, nommap, nokqfilter,
90 };
91 
92 extern struct cfdriver gpib_cd;
93 
94 #define GPIBUNIT(dev)		(minor(dev) & 0x0f)
95 
96 int gpibtimeout = 100000;	/* # of status tests before we give up */
97 
98 int
99 gpibmatch(parent, match, aux)
100 	struct device *parent;
101 	struct cfdata *match;
102 	void *aux;
103 {
104 
105 	return (1);
106 }
107 
108 void
109 gpibattach(parent, self, aux)
110 	struct device *parent, *self;
111 	void *aux;
112 {
113 	struct gpib_softc *sc = (struct gpib_softc *)self;
114 	struct cfdata *cf = sc->sc_dev.dv_cfdata;
115 	struct gpibdev_attach_args *gda = aux;
116 	struct gpib_attach_args ga;
117 	int address;
118 
119 	sc->sc_ic = gda->ga_ic;
120 
121 	/*
122 	 * If the configuration file specified a host address, then
123 	 * use it in favour of registers/switches or the default (30).
124 	 */
125 	if (cf->cf_loc[GPIBDEVCF_ADDRESS] != GPIBDEVCF_ADDRESS_DEFAULT)
126 		sc->sc_myaddr = cf->cf_loc[GPIBDEVCF_ADDRESS];
127 	else if (gda->ga_address != GPIBDEVCF_ADDRESS_DEFAULT)
128 		sc->sc_myaddr = gda->ga_address;
129 	else
130 		sc->sc_myaddr = 30;
131 
132 	printf(": host address %d\n", sc->sc_myaddr);
133 
134 	/* record our softc pointer */
135 	sc->sc_ic->bus = sc;
136 
137 	/* Initialize the slave request queue */
138 	TAILQ_INIT(&sc->sc_queue);
139 
140 	/* attach addressed devices */
141 	for (address=0; address<GPIB_NDEVS; address++) {
142 		ga.ga_ic = sc->sc_ic;
143 		ga.ga_address = address;
144 		(void) config_search_ia(gpibsubmatch1, &sc->sc_dev, "gpib", &ga);
145 	}
146 
147 	/* attach the wild-carded devices - probably protocol busses */
148 	ga.ga_ic = sc->sc_ic;
149 	(void) config_search_ia(gpibsubmatch2,  &sc->sc_dev, "gpib", &ga);
150 }
151 
152 int
153 gpibsubmatch1(parent, cf, ldesc, aux)
154 	struct device *parent;
155 	struct cfdata *cf;
156 	const locdesc_t *ldesc;
157 	void *aux;
158 {
159 	struct gpib_softc *sc = (struct gpib_softc *)parent;
160 	struct gpib_attach_args *ga = aux;
161 
162 	if (cf->cf_loc[GPIBCF_ADDRESS] != ga->ga_address)
163 		return (0);
164 
165 	if (cf->cf_loc[GPIBCF_ADDRESS] == sc->sc_myaddr)
166 		return (0);
167 
168 	if (config_match(parent, cf, ga) > 0) {
169 		if (gpib_alloc(sc, ga->ga_address))
170 			return (0);
171 		config_attach(parent, cf, ga, gpibprint);
172 		return (0);
173 	}
174 	return (0);
175 }
176 
177 int
178 gpibsubmatch2(parent, cf, aux)
179 	struct device *parent;
180 	struct cfdata *cf;
181 	const locdesc_t *ldesc;
182 	void *aux;
183 {
184 	struct gpib_attach_args *ga = aux;
185 
186 	if (cf->cf_loc[GPIBCF_ADDRESS] != GPIBCF_ADDRESS_DEFAULT)
187 		return (0);
188 
189 	ga->ga_address = GPIBCF_ADDRESS_DEFAULT;
190 	if (config_match(parent, cf, ga) > 0) {
191 		config_attach(parent, cf, ga, gpibdevprint);
192 		return (0);
193 	}
194 	return (0);
195 }
196 
197 int
198 gpibprint(aux, pnp)
199 	void *aux;
200 	const char *pnp;
201 {
202 	struct gpib_attach_args *ga = aux;
203 
204 	if (ga->ga_address != GPIBCF_ADDRESS_DEFAULT)
205 		printf(" address %d", ga->ga_address);
206 	return (UNCONF);
207 }
208 
209 int
210 gpibdevprint(aux, pnp)
211 	void *aux;
212 	const char *pnp;
213 {
214 
215 	if (pnp != NULL)
216 		printf("gpib at %s", pnp);
217 	return (UNCONF);
218 }
219 
220 /*
221  * Called by hardware driver, pass to device driver.
222  */
223 int
224 gpibintr(v)
225 	void *v;
226 {
227 	struct gpib_softc *sc = v;
228 	gpib_handle_t hdl;
229 
230 	DPRINTF(DBG_INTR, ("gpibintr: sc=%p\n", sc));
231 
232 	hdl = TAILQ_FIRST(&sc->sc_queue);
233 	(hdl->hq_callback)(hdl->hq_softc, GPIBCBF_INTR);
234 	return (0);
235 }
236 
237 /*
238  * Create a callback handle.
239  */
240 int
241 _gpibregister(sc, slave, callback, arg, hdl)
242 	struct gpib_softc *sc;
243 	int slave;
244 	gpib_callback_t callback;
245 	void *arg;
246 	gpib_handle_t *hdl;
247 {
248 
249 	MALLOC(*hdl, gpib_handle_t, sizeof(struct gpibqueue),
250 	    M_DEVBUF, M_NOWAIT);
251 	if (*hdl == NULL) {
252 		DPRINTF(DBG_FAIL, ("_gpibregister: can't allocate queue\n"));
253 		return (1);
254 	}
255 
256 	(*hdl)->hq_slave = slave;
257 	(*hdl)->hq_callback = callback;
258 	(*hdl)->hq_softc = arg;
259 
260 	return (0);
261 }
262 
263 /*
264  * Request exclusive access to the GPIB bus.
265  */
266 int
267 _gpibrequest(sc, hdl)
268 	struct gpib_softc *sc;
269 	gpib_handle_t hdl;
270 {
271 
272 	DPRINTF(DBG_FOLLOW, ("_gpibrequest: sc=%p hdl=%p\n", sc, hdl));
273 
274 	TAILQ_INSERT_TAIL(&sc->sc_queue, hdl, hq_list);
275 	if (TAILQ_FIRST(&sc->sc_queue) == hdl)
276 		return (1);
277 
278 	return (0);
279 }
280 
281 /*
282  * Release exclusive access to the GPIB bus.
283  */
284 void
285 _gpibrelease(sc, hdl)
286 	struct gpib_softc *sc;
287 	gpib_handle_t hdl;
288 {
289 
290 	DPRINTF(DBG_FOLLOW, ("_gpibrelease: sc=%p hdl=%p\n", sc, hdl));
291 
292 	TAILQ_REMOVE(&sc->sc_queue, hdl, hq_list);
293 	if ((hdl = TAILQ_FIRST(&sc->sc_queue)) != NULL)
294 		(*hdl->hq_callback)(hdl->hq_softc, GPIBCBF_START);
295 }
296 
297 
298 /*
299  * Asynchronous wait.
300  */
301 void
302 _gpibawait(sc)
303 	struct gpib_softc *sc;
304 {
305 	int slave;
306 
307 	DPRINTF(DBG_FOLLOW, ("_gpibawait: sc=%p\n", sc));
308 
309 	slave = TAILQ_FIRST(&sc->sc_queue)->hq_slave;
310 	(*sc->sc_ic->ppwatch)(sc->sc_ic->cookie, slave);
311 }
312 
313 /*
314  * Synchronous (spin) wait.
315  */
316 int
317 _gpibswait(sc, slave)
318 	struct gpib_softc *sc;
319 	int slave;
320 {
321 	int timo = gpibtimeout;
322 	int (*pptest)(void *, int);
323 
324 	DPRINTF(DBG_FOLLOW, ("_gpibswait: sc=%p\n", sc));
325 
326 	pptest = sc->sc_ic->pptest;
327 	while ((*pptest)(sc->sc_ic->cookie, slave) == 0) {
328 		if (--timo == 0) {
329 			printf("%s: swait timeout\n", sc->sc_dev.dv_xname);
330 			return(-1);
331 		}
332 	}
333 	return (0);
334 }
335 
336 /*
337  * Resource accounting: check if the address has already been
338  * claimed and allocated.
339  */
340 int
341 gpib_isalloc(sc, address)
342 	struct gpib_softc *sc;
343 	u_int8_t address;
344 {
345 
346 	DPRINTF(DBG_FOLLOW, ("gpib_isalloc: sc=%p address=%d\n", sc, address));
347 
348 #ifdef DIAGNOSTIC
349 	if (address >= GPIB_NDEVS)
350 		panic("gpib_isalloc: device address out of range");
351 #endif
352 
353 	return ((sc->sc_rmap & (1 << address)) != 0);
354 }
355 
356 /*
357  * Resource accounting: allocate the address.
358  */
359 int
360 gpib_alloc(sc, address)
361 	struct gpib_softc *sc;
362 	u_int8_t address;
363 {
364 
365 	DPRINTF(DBG_FOLLOW, ("gpib_alloc: sc=%p address=%d\n", sc, address));
366 
367 #ifdef DIAGNOSTIC
368 	if (address >= GPIB_NDEVS)
369 		panic("gpib_alloc: device address out of range");
370 #endif
371 
372 	if (!gpib_isalloc(sc, address)) {
373 		sc->sc_rmap |= (1 << address);
374 		return (0);
375 	}
376 	return (1);
377 }
378 
379 /*
380  * Resource accounting: deallocate the address.
381  */
382 void
383 gpib_dealloc(sc, address)
384 	struct gpib_softc *sc;
385 	u_int8_t address;
386 {
387 
388 	DPRINTF(DBG_FOLLOW, ("gpib_free: sc=%p address=%d\n", sc, address));
389 
390 #ifdef DIAGNOSTIC
391 	if (address >= GPIB_NDEVS)
392 		panic("gpib_free: device address out of range");
393 
394 	if (!gpib_isalloc(sc, address))
395 		panic("gpib_free: not allocated");
396 #endif
397 
398 	sc->sc_rmap &= ~(1 << address);
399 }
400 
401 int
402 _gpibsend(sc, slave, sec, ptr, origcnt)
403 	struct gpib_softc *sc;
404 	int slave;
405 	int sec;
406 	void *ptr;
407 	int origcnt;
408 {
409 	int rv;
410 	int cnt = 0;
411 	u_int8_t cmds[4];
412 	int i = 0;
413 
414 	DPRINTF(DBG_FOLLOW,
415 	    ("_gpibsend: sc=%p slave %d sec=%d ptr=%p cnt=%d\n",
416 	    sc, slave, sec, ptr, origcnt));
417 
418 	/*
419 	 * For compatibility, call the hardware driver directly.
420 	 */
421 	if (sc->sc_ic->send != NULL) {
422 		rv = (*sc->sc_ic->send)(sc->sc_ic->cookie,
423 			slave, sec, ptr, origcnt);
424 		return (rv);
425 	}
426 
427 	if ((*sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
428 		goto senderror;
429 	cmds[i++] = GPIBCMD_UNL;
430 	cmds[i++] = GPIBCMD_TAG | sc->sc_myaddr;
431 	cmds[i++] = GPIBCMD_LAG | slave;
432 	if (sec >= 0 || sec == -2) {
433 		if (sec == -2)		/* selected device clear KLUDGE */
434 			cmds[i++] = GPIBCMD_SDC;
435 		else
436 			cmds[i++] = GPIBCMD_SCG | sec;
437 	}
438 	if ((*sc->sc_ic->sendcmds)(sc->sc_ic->cookie, cmds, i) != i)
439 		goto senderror;
440 	if ((*sc->sc_ic->gts)(sc->sc_ic->cookie))
441 		goto senderror;
442 	if (origcnt) {
443 		cnt = (*sc->sc_ic->senddata)(sc->sc_ic->cookie, ptr, origcnt);
444 		if (cnt != origcnt)
445 			goto senderror;
446 		if ((*sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
447 			goto senderror;
448 	}
449 	return (origcnt);
450 
451 senderror:
452 	(*sc->sc_ic->ifc)(sc->sc_ic->cookie);
453 	DPRINTF(DBG_FAIL,
454 	    ("%s: _gpibsend failed: slave %d, sec %x, sent %d of %d bytes\n",
455 	    sc->sc_dev.dv_xname, slave, sec, cnt, origcnt));
456 	return (cnt);
457 }
458 
459 int
460 _gpibrecv(sc, slave, sec, ptr, origcnt)
461 	struct gpib_softc *sc;
462 	int slave;
463 	int sec;
464 	void *ptr;
465 	int origcnt;
466 {
467 	int rv;
468 	u_int8_t cmds[4];
469 	int cnt = 0;
470 	int i = 0;
471 
472 	DPRINTF(DBG_FOLLOW,
473 	    ("_gpibrecv: sc=%p slave=%d sec=%d buf=%p cnt=%d\n",
474 	    sc, slave, sec, ptr, origcnt));
475 
476 	/*
477 	 * For compatibility, call the hardware driver directly.
478 	 */
479 	if (sc->sc_ic->recv != NULL) {
480 		rv = (*sc->sc_ic->recv)(sc->sc_ic->cookie,
481 			slave, sec, ptr, origcnt);
482 		return (rv);
483 	}
484 
485 	/*
486 	 * slave < 0 implies continuation of a previous receive
487 	 * that probably timed out.
488 	 */
489 	if (slave >= 0) {
490 		if ((*sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
491 			goto recverror;
492 		cmds[i++] = GPIBCMD_UNL;
493 		cmds[i++] = GPIBCMD_LAG | sc->sc_myaddr;
494 		cmds[i++] = GPIBCMD_TAG | slave;
495 		if (sec >= 0)
496 			cmds[i++] = GPIBCMD_SCG | sec;
497 		if ((*sc->sc_ic->sendcmds)(sc->sc_ic->cookie, cmds, i) != i)
498 			goto recverror;
499 		if ((*sc->sc_ic->gts)(sc->sc_ic->cookie))
500 			goto recverror;
501 	}
502 	if (origcnt) {
503 		cnt = (*sc->sc_ic->recvdata)(sc->sc_ic->cookie, ptr, origcnt);
504 		if (cnt != origcnt)
505 			goto recverror;
506 		if ((sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
507 			goto recverror;
508 		cmds[0] = (slave == GPIB_BROADCAST_ADDR) ?
509 		    GPIBCMD_UNA : GPIBCMD_UNT;
510 		if ((*sc->sc_ic->sendcmds)(sc->sc_ic->cookie, cmds, 1) != 1)
511 			goto recverror;
512 	}
513 	return (origcnt);
514 
515 recverror:
516 	(*sc->sc_ic->ifc)(sc->sc_ic->cookie);
517 	DPRINTF(DBG_FAIL,
518 	    ("_gpibrecv: failed, sc=%p slave %d, sec %x, got %d of %d bytes\n",
519 	    sc, slave, sec, cnt, origcnt));
520 	return (cnt);
521 }
522 
523 /*
524  * /dev/gpib? interface
525  */
526 
527 int
528 gpibopen(dev, flags, mode, p)
529 	dev_t dev;
530 	int flags, mode;
531 	struct proc *p;
532 {
533 	struct gpib_softc *sc;
534 
535 	sc = device_lookup(&gpib_cd, GPIBUNIT(dev));
536 	if (sc == NULL)
537 		return (ENXIO);
538 
539 	DPRINTF(DBG_FOLLOW, ("gpibopen: sc=%p\n", sc));
540 
541 	if (sc->sc_flags & GPIBF_ACTIVE)
542 		return (EBUSY);
543 	sc->sc_flags |= GPIBF_ACTIVE;
544 
545 	return (0);
546 }
547 
548 int
549 gpibclose(dev, flag, mode, p)
550 	dev_t dev;
551 	int flag, mode;
552 	struct proc *p;
553 {
554 	struct gpib_softc *sc;
555 
556 	sc = device_lookup(&gpib_cd, GPIBUNIT(dev));
557 	if (sc == NULL)
558 		return (ENXIO);
559 
560 	DPRINTF(DBG_FOLLOW, ("gpibclose: sc=%p\n", sc));
561 
562 	sc->sc_flags &= ~GPIBF_ACTIVE;
563 
564 	return (0);
565 }
566 
567 int
568 gpibread(dev, uio, flags)
569 	dev_t dev;
570 	struct uio *uio;
571 	int flags;
572 {
573 	struct gpib_softc *sc;
574 
575 	sc = device_lookup(&gpib_cd, GPIBUNIT(dev));
576 	if (sc == NULL)
577 		return (ENXIO);
578 
579 	DPRINTF(DBG_FOLLOW, ("gpibread: sc=%p\n", sc));
580 
581 	return (EOPNOTSUPP);
582 }
583 
584 int
585 gpibwrite(dev, uio, flags)
586 	dev_t dev;
587 	struct uio *uio;
588 	int flags;
589 {
590 	struct gpib_softc *sc;
591 
592 	sc = device_lookup(&gpib_cd, GPIBUNIT(dev));
593 	if (sc == NULL)
594 		return (ENXIO);
595 
596 	DPRINTF(DBG_FOLLOW, ("gpibwrite: sc=%p\n", sc));
597 
598 	return (EOPNOTSUPP);
599 }
600 
601 int
602 gpibioctl(dev, cmd, data, flag, p)
603 	dev_t dev;
604 	u_long cmd;
605 	caddr_t data;
606 	int flag;
607 	struct proc *p;
608 {
609 	struct gpib_softc *sc;
610 
611 	sc = device_lookup(&gpib_cd, GPIBUNIT(dev));
612 	if (sc == NULL)
613 		return (ENXIO);
614 
615 	DPRINTF(DBG_FOLLOW, ("gpibioctl(%lu, '%c',%lu): sc=%p\n",
616 	    IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd & 0xff, sc));
617 
618 	switch (cmd) {
619 	case GPIB_INFO:
620 		(*(int *)data) = 0xa5a5a5a5;
621 		break;
622 	}
623 
624 	return (EINVAL);
625 }
626 
627 int
628 gpibpoll(dev, events, p)
629 	dev_t dev;
630 	int events;
631 	struct proc *p;
632 {
633 	struct gpib_softc *sc;
634 
635 	sc = device_lookup(&gpib_cd, GPIBUNIT(dev));
636 	if (sc == NULL)
637 		return (ENXIO);
638 
639 	DPRINTF(DBG_FOLLOW, ("gpibpoll: sc=%p\n", sc));
640 
641 	return (0);
642 }
643