xref: /netbsd/sys/dev/gpib/ppi.c (revision 6550d01e)
1 /*	$NetBSD: ppi.c,v 1.19 2009/09/12 18:44:36 tsutsui 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.19 2009/09/12 18:44:36 tsutsui 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(device_t, cfdata_t, void *);
107 void	ppiattach(device_t, device_t, 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(device_t parent, cfdata_t match, void *aux)
147 {
148 
149 	return (1);
150 }
151 
152 void
153 ppiattach(device_t parent, device_t self, void *aux)
154 {
155 	struct ppi_softc *sc = device_private(self);
156 	struct gpib_attach_args *ga = aux;
157 
158 	printf("\n");
159 
160 	sc->sc_ic = ga->ga_ic;
161 	sc->sc_address = ga->ga_address;
162 
163 	callout_init(&sc->sc_timo_ch, 0);
164 	callout_init(&sc->sc_start_ch, 0);
165 
166 	if (gpibregister(sc->sc_ic, sc->sc_address, ppicallback, sc,
167 	    &sc->sc_hdl)) {
168 		aprint_error_dev(&sc->sc_dev, "can't register callback\n");
169 		return;
170 	}
171 
172 	sc->sc_flags = PPIF_ALIVE;
173 }
174 
175 int
176 ppiopen(dev_t dev, int flags, int fmt, struct lwp *l)
177 {
178 	struct ppi_softc *sc;
179 
180 	sc = device_lookup_private(&ppi_cd, UNIT(dev));
181 	if (sc == NULL)
182 		return (ENXIO);
183 
184 	if ((sc->sc_flags & PPIF_ALIVE) == 0)
185 		return (ENXIO);
186 
187 	DPRINTF(PDB_FOLLOW, ("ppiopen(%" PRIx64 ", %x): flags %x\n",
188 	    dev, flags, sc->sc_flags));
189 
190 	if (sc->sc_flags & PPIF_OPEN)
191 		return (EBUSY);
192 	sc->sc_flags |= PPIF_OPEN;
193 	sc->sc_burst = PPI_BURST;
194 	sc->sc_timo = ppimstohz(PPI_TIMO);
195 	sc->sc_delay = ppimstohz(PPI_DELAY);
196 	sc->sc_sec = -1;
197 	return (0);
198 }
199 
200 int
201 ppiclose(dev_t dev, int flags, int fmt, struct lwp *l)
202 {
203 	struct ppi_softc *sc;
204 
205 	sc = device_lookup_private(&ppi_cd, UNIT(dev));
206 
207 	DPRINTF(PDB_FOLLOW, ("ppiclose(%" PRIx64 ", %x): flags %x\n",
208 		       dev, flags, sc->sc_flags));
209 
210 	sc->sc_flags &= ~PPIF_OPEN;
211 	return (0);
212 }
213 
214 void
215 ppicallback(void *v, int action)
216 {
217 	struct ppi_softc *sc = v;
218 
219 	DPRINTF(PDB_FOLLOW, ("ppicallback: v=%p, action=%d\n", v, action));
220 
221 	switch (action) {
222 	case GPIBCBF_START:
223 		ppistart(sc);
224 	case GPIBCBF_INTR:
225 		/* no-op */
226 		break;
227 #ifdef DEBUG
228 	default:
229 		DPRINTF(PDB_FOLLOW, ("ppicallback: unknown action %d\n",
230 		    action));
231 		break;
232 #endif
233 	}
234 }
235 
236 void
237 ppistart(void *v)
238 {
239 	struct ppi_softc *sc = v;
240 
241 	DPRINTF(PDB_FOLLOW, ("ppistart(%x)\n", device_unit(&sc->sc_dev)));
242 
243 	sc->sc_flags &= ~PPIF_DELAY;
244 	wakeup(sc);
245 }
246 
247 void
248 ppitimo(void *arg)
249 {
250 	struct ppi_softc *sc = arg;
251 
252 	DPRINTF(PDB_FOLLOW, ("ppitimo(%x)\n", device_unit(&sc->sc_dev)));
253 
254 	sc->sc_flags &= ~(PPIF_UIO|PPIF_TIMO);
255 	wakeup(sc);
256 }
257 
258 int
259 ppiread(dev_t dev, struct uio *uio, int flags)
260 {
261 
262 	DPRINTF(PDB_FOLLOW, ("ppiread(%" PRIx64 ", %p)\n", dev, uio));
263 
264 	return (ppirw(dev, uio));
265 }
266 
267 int
268 ppiwrite(dev_t dev, struct uio *uio, int flags)
269 {
270 
271 	DPRINTF(PDB_FOLLOW, ("ppiwrite(%" PRIx64 ", %p)\n", dev, uio));
272 
273 	return (ppirw(dev, uio));
274 }
275 
276 int
277 ppirw(dev_t dev, struct uio *uio)
278 {
279 	struct ppi_softc *sc = device_lookup_private(&ppi_cd, UNIT(dev));
280 	int s1, s2, len, cnt;
281 	char *cp;
282 	int error = 0, gotdata = 0;
283 	int buflen, address;
284 	char *buf;
285 
286 	if (uio->uio_resid == 0)
287 		return (0);
288 
289 	address = sc->sc_address;
290 
291 	DPRINTF(PDB_FOLLOW|PDB_IO,
292 	    ("ppirw(%" PRIx64 ", %p, %c): burst %d, timo %d, resid %x\n",
293 	    dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
294 	    sc->sc_burst, sc->sc_timo, uio->uio_resid));
295 
296 	buflen = min(sc->sc_burst, uio->uio_resid);
297 	buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
298 	sc->sc_flags |= PPIF_UIO;
299 	if (sc->sc_timo > 0) {
300 		sc->sc_flags |= PPIF_TIMO;
301 		callout_reset(&sc->sc_timo_ch, sc->sc_timo, ppitimo, sc);
302 	}
303 	len = cnt = 0;
304 	while (uio->uio_resid > 0) {
305 		len = min(buflen, uio->uio_resid);
306 		cp = buf;
307 		if (uio->uio_rw == UIO_WRITE) {
308 			error = uiomove(cp, len, uio);
309 			if (error)
310 				break;
311 		}
312 again:
313 		s1 = splsoftclock();
314 		s2 = splbio();
315 		if (sc->sc_flags & PPIF_UIO) {
316 			if (gpibrequest(sc->sc_ic, sc->sc_hdl) == 0)
317 				(void) tsleep(sc, PRIBIO + 1, "ppirw", 0);
318 		}
319 		/*
320 		 * Check if we timed out during sleep or uiomove
321 		 */
322 		splx(s2);
323 		if ((sc->sc_flags & PPIF_UIO) == 0) {
324 			DPRINTF(PDB_IO,
325 			    ("ppirw: uiomove/sleep timo, flags %x\n",
326 			    sc->sc_flags));
327 			if (sc->sc_flags & PPIF_TIMO) {
328 				callout_stop(&sc->sc_timo_ch);
329 				sc->sc_flags &= ~PPIF_TIMO;
330 			}
331 			splx(s1);
332 			break;
333 		}
334 		splx(s1);
335 		/*
336 		 * Perform the operation
337 		 */
338 		if (uio->uio_rw == UIO_WRITE)
339 			cnt = gpibsend(sc->sc_ic, address, sc->sc_sec,
340 			    cp, len);
341 		else
342 			cnt = gpibrecv(sc->sc_ic, address, sc->sc_sec,
343 			    cp, len);
344 		s1 = splbio();
345 		gpibrelease(sc->sc_ic, sc->sc_hdl);
346 		DPRINTF(PDB_IO, ("ppirw: %s(%d, %x, %p, %d) -> %d\n",
347 		    uio->uio_rw == UIO_READ ? "recv" : "send",
348 		    address, sc->sc_sec, cp, len, cnt));
349 		splx(s1);
350 		if (uio->uio_rw == UIO_READ) {
351 			if (cnt) {
352 				error = uiomove(cp, cnt, uio);
353 				if (error)
354 					break;
355 				gotdata++;
356 			}
357 			/*
358 			 * Didn't get anything this time, but did in the past.
359 			 * Consider us done.
360 			 */
361 			else if (gotdata)
362 				break;
363 		}
364 		s1 = splsoftclock();
365 		/*
366 		 * Operation timeout (or non-blocking), quit now.
367 		 */
368 		if ((sc->sc_flags & PPIF_UIO) == 0) {
369 			DPRINTF(PDB_IO, ("ppirw: timeout/done\n"));
370 			splx(s1);
371 			break;
372 		}
373 		/*
374 		 * Implement inter-read delay
375 		 */
376 		if (sc->sc_delay > 0) {
377 			sc->sc_flags |= PPIF_DELAY;
378 			callout_reset(&sc->sc_start_ch, sc->sc_delay,
379 			    ppistart, sc);
380 			error = tsleep(sc, (PCATCH|PZERO) + 1, "gpib", 0);
381 			if (error) {
382 				splx(s1);
383 				break;
384 			}
385 		}
386 		splx(s1);
387 		/*
388 		 * Must not call uiomove again til we've used all data
389 		 * that we already grabbed.
390 		 */
391 		if (uio->uio_rw == UIO_WRITE && cnt != len) {
392 			cp += cnt;
393 			len -= cnt;
394 			cnt = 0;
395 			goto again;
396 		}
397 	}
398 	s1 = splsoftclock();
399 	if (sc->sc_flags & PPIF_TIMO) {
400 		callout_stop(&sc->sc_timo_ch);
401 		sc->sc_flags &= ~PPIF_TIMO;
402 	}
403 	if (sc->sc_flags & PPIF_DELAY) {
404 		callout_stop(&sc->sc_start_ch);
405 		sc->sc_flags &= ~PPIF_DELAY;
406 	}
407 	splx(s1);
408 	/*
409 	 * Adjust for those chars that we uiomove'ed but never wrote
410 	 */
411 	if (uio->uio_rw == UIO_WRITE && cnt != len) {
412 		uio->uio_resid += (len - cnt);
413 		DPRINTF(PDB_IO, ("ppirw: short write, adjust by %d\n",
414 		    len - cnt));
415 	}
416 	free(buf, M_DEVBUF);
417 	DPRINTF(PDB_FOLLOW|PDB_IO, ("ppirw: return %d, resid %d\n",
418 	    error, uio->uio_resid));
419 	return (error);
420 }
421 
422 int
423 ppiioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
424 {
425 	struct ppi_softc *sc = device_lookup_private(&ppi_cd, UNIT(dev));
426 	struct ppiparam *pp, *upp;
427 	int error = 0;
428 
429 	switch (cmd) {
430 	case PPIIOCGPARAM:
431 		pp = &sc->sc_param;
432 		upp = (struct ppiparam *)data;
433 		upp->burst = pp->burst;
434 		upp->timo = ppihztoms(pp->timo);
435 		upp->delay = ppihztoms(pp->delay);
436 		break;
437 	case PPIIOCSPARAM:
438 		pp = &sc->sc_param;
439 		upp = (struct ppiparam *)data;
440 		if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX ||
441 		    upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX)
442 			return (EINVAL);
443 		pp->burst = upp->burst;
444 		pp->timo = ppimstohz(upp->timo);
445 		pp->delay = ppimstohz(upp->delay);
446 		break;
447 	case PPIIOCSSEC:
448 		sc->sc_sec = *(int *)data;
449 		break;
450 	default:
451 		return (EINVAL);
452 	}
453 	return (error);
454 }
455 
456 int
457 ppihztoms(int h)
458 {
459 	extern int hz;
460 	int m = h;
461 
462 	if (m > 0)
463 		m = m * 1000 / hz;
464 	return (m);
465 }
466 
467 int
468 ppimstohz(int m)
469 {
470 	extern int hz;
471 	int h = m;
472 
473 	if (h > 0) {
474 		h = h * hz / 1000;
475 		if (h == 0)
476 			h = 1000 / hz;
477 	}
478 	return (h);
479 }
480