xref: /netbsd-src/sys/dev/gpib/ppi.c (revision 466a16a118933bd295a8a104f095714fadf9cf68)
1 /*	$NetBSD: ppi.c,v 1.13 2008/06/12 21:45:39 cegger Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996-2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1982, 1990, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *	@(#)ppi.c	8.1 (Berkeley) 6/16/93
61  */
62 
63 /*
64  * Printer/Plotter GPIB interface
65  */
66 
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: ppi.c,v 1.13 2008/06/12 21:45:39 cegger Exp $");
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/callout.h>
73 #include <sys/conf.h>
74 #include <sys/device.h>
75 #include <sys/malloc.h>
76 #include <sys/proc.h>
77 #include <sys/uio.h>
78 
79 #include <dev/gpib/gpibvar.h>
80 
81 #include <dev/gpib/ppiio.h>
82 
83 struct	ppi_softc {
84 	struct device sc_dev;
85 	gpib_chipset_tag_t sc_ic;
86 	gpib_handle_t sc_hdl;
87 
88 	int sc_address;			/* GPIB address */
89 	int	sc_flags;
90 	int	sc_sec;
91 	struct	ppiparam sc_param;
92 #define sc_burst sc_param.burst
93 #define sc_timo  sc_param.timo
94 #define sc_delay sc_param.delay
95 	struct	callout sc_timo_ch;
96 	struct	callout sc_start_ch;
97 };
98 
99 /* sc_flags values */
100 #define	PPIF_ALIVE	0x01
101 #define	PPIF_OPEN	0x02
102 #define PPIF_UIO	0x04
103 #define PPIF_TIMO	0x08
104 #define PPIF_DELAY	0x10
105 
106 int	ppimatch(struct device *, struct cfdata *, void *);
107 void	ppiattach(struct device *, struct device *, void *);
108 
109 CFATTACH_DECL(ppi, sizeof(struct ppi_softc),
110 	ppimatch, ppiattach, NULL, NULL);
111 
112 extern struct cfdriver ppi_cd;
113 
114 void	ppicallback(void *, int);
115 void	ppistart(void *);
116 
117 void	ppitimo(void *);
118 int	ppirw(dev_t, struct uio *);
119 int	ppihztoms(int);
120 int	ppimstohz(int);
121 
122 dev_type_open(ppiopen);
123 dev_type_close(ppiclose);
124 dev_type_read(ppiread);
125 dev_type_write(ppiwrite);
126 dev_type_ioctl(ppiioctl);
127 
128 const struct cdevsw ppi_cdevsw = {
129         ppiopen, ppiclose, ppiread, ppiwrite, ppiioctl,
130         nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
131 };
132 
133 #define UNIT(x)		minor(x)
134 
135 #ifdef DEBUG
136 int	ppidebug = 0x80;
137 #define PDB_FOLLOW	0x01
138 #define PDB_IO		0x02
139 #define PDB_NOCHECK	0x80
140 #define DPRINTF(mask, str)	if (ppidebug & (mask)) printf str
141 #else
142 #define DPRINTF(mask, str)	/* nothing */
143 #endif
144 
145 int
146 ppimatch(parent, match, aux)
147 	struct device *parent;
148 	struct cfdata *match;
149 	void *aux;
150 {
151 
152 	return (1);
153 }
154 
155 void
156 ppiattach(parent, self, aux)
157 	struct device *parent, *self;
158 	void *aux;
159 {
160 	struct ppi_softc *sc = device_private(self);
161 	struct gpib_attach_args *ga = aux;
162 
163 	printf("\n");
164 
165 	sc->sc_ic = ga->ga_ic;
166 	sc->sc_address = ga->ga_address;
167 
168 	callout_init(&sc->sc_timo_ch, 0);
169 	callout_init(&sc->sc_start_ch, 0);
170 
171 	if (gpibregister(sc->sc_ic, sc->sc_address, ppicallback, sc,
172 	    &sc->sc_hdl)) {
173 		aprint_error_dev(&sc->sc_dev, "can't register callback\n");
174 		return;
175 	}
176 
177 	sc->sc_flags = PPIF_ALIVE;
178 }
179 
180 int
181 ppiopen(dev_t dev, int flags, int fmt, struct lwp *l)
182 {
183 	struct ppi_softc *sc;
184 
185 	sc = device_lookup_private(&ppi_cd, UNIT(dev));
186 	if (sc == NULL)
187 		return (ENXIO);
188 
189 	if (sc->sc_flags & PPIF_ALIVE) == 0)
190 		return (ENXIO);
191 
192 	DPRINTF(PDB_FOLLOW, ("ppiopen(%x, %x): flags %x\n",
193 	    dev, flags, sc->sc_flags));
194 
195 	if (sc->sc_flags & PPIF_OPEN)
196 		return (EBUSY);
197 	sc->sc_flags |= PPIF_OPEN;
198 	sc->sc_burst = PPI_BURST;
199 	sc->sc_timo = ppimstohz(PPI_TIMO);
200 	sc->sc_delay = ppimstohz(PPI_DELAY);
201 	sc->sc_sec = -1;
202 	return (0);
203 }
204 
205 int
206 ppiclose(dev_t dev, int flags, int fmt, struct lwp *l)
207 {
208 	struct ppi_softc *sc;
209 
210 	sc = device_lookup_private(&ppi_cd, UNIT(dev));
211 
212 	DPRINTF(PDB_FOLLOW, ("ppiclose(%x, %x): flags %x\n",
213 		       dev, flags, sc->sc_flags));
214 
215 	sc->sc_flags &= ~PPIF_OPEN;
216 	return (0);
217 }
218 
219 void
220 ppicallback(v, action)
221 	void *v;
222 	int action;
223 {
224 	struct ppi_softc *sc = v;
225 
226 	DPRINTF(PDB_FOLLOW, ("ppicallback: v=%p, action=%d\n", v, action));
227 
228 	switch (action) {
229 	case GPIBCBF_START:
230 		ppistart(sc);
231 	case GPIBCBF_INTR:
232 		/* no-op */
233 		break;
234 #ifdef DEBUG
235 	default:
236 		DPRINTF(PDB_FOLLOW, ("ppicallback: unknown action %d\n",
237 		    action));
238 		break;
239 #endif
240 	}
241 }
242 
243 void
244 ppistart(void *v)
245 {
246 	struct ppi_softc *sc = v;
247 
248 	DPRINTF(PDB_FOLLOW, ("ppistart(%x)\n", device_unit(&sc->sc_dev)));
249 
250 	sc->sc_flags &= ~PPIF_DELAY;
251 	wakeup(sc);
252 }
253 
254 void
255 ppitimo(void *arg)
256 {
257 	struct ppi_softc *sc = arg;
258 
259 	DPRINTF(PDB_FOLLOW, ("ppitimo(%x)\n", device_unit(&sc->sc_dev)));
260 
261 	sc->sc_flags &= ~(PPIF_UIO|PPIF_TIMO);
262 	wakeup(sc);
263 }
264 
265 int
266 ppiread(dev_t dev, struct uio *uio, int flags)
267 {
268 
269 	DPRINTF(PDB_FOLLOW, ("ppiread(%x, %p)\n", dev, uio));
270 
271 	return (ppirw(dev, uio));
272 }
273 
274 int
275 ppiwrite(dev_t dev, struct uio *uio, int flags)
276 {
277 
278 	DPRINTF(PDB_FOLLOW, ("ppiwrite(%x, %p)\n", dev, uio));
279 
280 	return (ppirw(dev, uio));
281 }
282 
283 int
284 ppirw(dev_t dev, struct uio *uio)
285 {
286 	struct ppi_softc *sc = device_lookup_private(&ppi_cd, UNIT(dev));
287 	int s1, s2, len, cnt;
288 	char *cp;
289 	int error = 0, gotdata = 0;
290 	int buflen, address;
291 	char *buf;
292 
293 	if (uio->uio_resid == 0)
294 		return (0);
295 
296 	address = sc->sc_address;
297 
298 	DPRINTF(PDB_FOLLOW|PDB_IO,
299 	    ("ppirw(%x, %p, %c): burst %d, timo %d, resid %x\n",
300 	    dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
301 	    sc->sc_burst, sc->sc_timo, uio->uio_resid));
302 
303 	buflen = min(sc->sc_burst, uio->uio_resid);
304 	buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
305 	sc->sc_flags |= PPIF_UIO;
306 	if (sc->sc_timo > 0) {
307 		sc->sc_flags |= PPIF_TIMO;
308 		callout_reset(&sc->sc_timo_ch, sc->sc_timo, ppitimo, sc);
309 	}
310 	len = cnt = 0;
311 	while (uio->uio_resid > 0) {
312 		len = min(buflen, uio->uio_resid);
313 		cp = buf;
314 		if (uio->uio_rw == UIO_WRITE) {
315 			error = uiomove(cp, len, uio);
316 			if (error)
317 				break;
318 		}
319 again:
320 		s1 = splsoftclock();
321 		s2 = splbio();
322 		if (sc->sc_flags & PPIF_UIO) {
323 			if (gpibrequest(sc->sc_ic, sc->sc_hdl) == 0)
324 				(void) tsleep(sc, PRIBIO + 1, "ppirw", 0);
325 		}
326 		/*
327 		 * Check if we timed out during sleep or uiomove
328 		 */
329 		splx(s2);
330 		if ((sc->sc_flags & PPIF_UIO) == 0) {
331 			DPRINTF(PDB_IO,
332 			    ("ppirw: uiomove/sleep timo, flags %x\n",
333 			    sc->sc_flags));
334 			if (sc->sc_flags & PPIF_TIMO) {
335 				callout_stop(&sc->sc_timo_ch);
336 				sc->sc_flags &= ~PPIF_TIMO;
337 			}
338 			splx(s1);
339 			break;
340 		}
341 		splx(s1);
342 		/*
343 		 * Perform the operation
344 		 */
345 		if (uio->uio_rw == UIO_WRITE)
346 			cnt = gpibsend(sc->sc_ic, address, sc->sc_sec,
347 			    cp, len);
348 		else
349 			cnt = gpibrecv(sc->sc_ic, address, sc->sc_sec,
350 			    cp, len);
351 		s1 = splbio();
352 		gpibrelease(sc->sc_ic, sc->sc_hdl);
353 		DPRINTF(PDB_IO, ("ppirw: %s(%d, %x, %p, %d) -> %d\n",
354 		    uio->uio_rw == UIO_READ ? "recv" : "send",
355 		    address, sc->sc_sec, cp, len, cnt));
356 		splx(s1);
357 		if (uio->uio_rw == UIO_READ) {
358 			if (cnt) {
359 				error = uiomove(cp, cnt, uio);
360 				if (error)
361 					break;
362 				gotdata++;
363 			}
364 			/*
365 			 * Didn't get anything this time, but did in the past.
366 			 * Consider us done.
367 			 */
368 			else if (gotdata)
369 				break;
370 		}
371 		s1 = splsoftclock();
372 		/*
373 		 * Operation timeout (or non-blocking), quit now.
374 		 */
375 		if ((sc->sc_flags & PPIF_UIO) == 0) {
376 			DPRINTF(PDB_IO, ("ppirw: timeout/done\n"));
377 			splx(s1);
378 			break;
379 		}
380 		/*
381 		 * Implement inter-read delay
382 		 */
383 		if (sc->sc_delay > 0) {
384 			sc->sc_flags |= PPIF_DELAY;
385 			callout_reset(&sc->sc_start_ch, sc->sc_delay,
386 			    ppistart, sc);
387 			error = tsleep(sc, (PCATCH|PZERO) + 1, "gpib", 0);
388 			if (error) {
389 				splx(s1);
390 				break;
391 			}
392 		}
393 		splx(s1);
394 		/*
395 		 * Must not call uiomove again til we've used all data
396 		 * that we already grabbed.
397 		 */
398 		if (uio->uio_rw == UIO_WRITE && cnt != len) {
399 			cp += cnt;
400 			len -= cnt;
401 			cnt = 0;
402 			goto again;
403 		}
404 	}
405 	s1 = splsoftclock();
406 	if (sc->sc_flags & PPIF_TIMO) {
407 		callout_stop(&sc->sc_timo_ch);
408 		sc->sc_flags &= ~PPIF_TIMO;
409 	}
410 	if (sc->sc_flags & PPIF_DELAY) {
411 		callout_stop(&sc->sc_start_ch);
412 		sc->sc_flags &= ~PPIF_DELAY;
413 	}
414 	splx(s1);
415 	/*
416 	 * Adjust for those chars that we uiomove'ed but never wrote
417 	 */
418 	if (uio->uio_rw == UIO_WRITE && cnt != len) {
419 		uio->uio_resid += (len - cnt);
420 		DPRINTF(PDB_IO, ("ppirw: short write, adjust by %d\n",
421 		    len - cnt));
422 	}
423 	free(buf, M_DEVBUF);
424 	DPRINTF(PDB_FOLLOW|PDB_IO, ("ppirw: return %d, resid %d\n",
425 	    error, uio->uio_resid));
426 	return (error);
427 }
428 
429 int
430 ppiioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
431 {
432 	struct ppi_softc *sc = device_lookup_private(&ppi_cd, UNIT(dev));
433 	struct ppiparam *pp, *upp;
434 	int error = 0;
435 
436 	switch (cmd) {
437 	case PPIIOCGPARAM:
438 		pp = &sc->sc_param;
439 		upp = (struct ppiparam *)data;
440 		upp->burst = pp->burst;
441 		upp->timo = ppihztoms(pp->timo);
442 		upp->delay = ppihztoms(pp->delay);
443 		break;
444 	case PPIIOCSPARAM:
445 		pp = &sc->sc_param;
446 		upp = (struct ppiparam *)data;
447 		if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX ||
448 		    upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX)
449 			return (EINVAL);
450 		pp->burst = upp->burst;
451 		pp->timo = ppimstohz(upp->timo);
452 		pp->delay = ppimstohz(upp->delay);
453 		break;
454 	case PPIIOCSSEC:
455 		sc->sc_sec = *(int *)data;
456 		break;
457 	default:
458 		return (EINVAL);
459 	}
460 	return (error);
461 }
462 
463 int
464 ppihztoms(int h)
465 {
466 	extern int hz;
467 	int m = h;
468 
469 	if (m > 0)
470 		m = m * 1000 / hz;
471 	return (m);
472 }
473 
474 int
475 ppimstohz(int m)
476 {
477 	extern int hz;
478 	int h = m;
479 
480 	if (h > 0) {
481 		h = h * hz / 1000;
482 		if (h == 0)
483 			h = 1000 / hz;
484 	}
485 	return (h);
486 }
487