1 /* $NetBSD: ppi.c,v 1.18 2009/09/12 18:43:03 tsutsui Exp $ */
4 * Copyright (c) 1996-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright (c) 1982, 1990, 1993
34 * The Regents of the University of California. All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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
60 * @(#)ppi.c 8.1 (Berkeley) 6/16/93
64 * Printer/Plotter GPIB interface
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: ppi.c,v 1.18 2009/09/12 18:43:03 tsutsui Exp $");
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/callout.h>
74 #include <sys/device.h>
75 #include <sys/malloc.h>
79 #include <dev/gpib/gpibvar.h>
81 #include <dev/gpib/ppiio.h>
85 gpib_chipset_tag_t sc_ic
;
88 int sc_address
; /* GPIB address */
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
;
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
106 int ppimatch(device_t
, cfdata_t
, void *);
107 void ppiattach(device_t
, device_t
, void *);
109 CFATTACH_DECL(ppi
, sizeof(struct ppi_softc
),
110 ppimatch
, ppiattach
, NULL
, NULL
);
112 extern struct cfdriver ppi_cd
;
114 void ppicallback(void *, int);
115 void ppistart(void *);
117 void ppitimo(void *);
118 int ppirw(dev_t
, struct uio
*);
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
);
128 const struct cdevsw ppi_cdevsw
= {
129 ppiopen
, ppiclose
, ppiread
, ppiwrite
, ppiioctl
,
130 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
133 #define UNIT(x) minor(x)
137 #define PDB_FOLLOW 0x01
139 #define PDB_NOCHECK 0x80
140 #define DPRINTF(mask, str) if (ppidebug & (mask)) printf str
142 #define DPRINTF(mask, str) /* nothing */
146 ppimatch(device_t parent
, cfdata_t match
, void *aux
)
153 ppiattach(device_t parent
, device_t self
, void *aux
)
155 struct ppi_softc
*sc
= device_private(self
);
156 struct gpib_attach_args
*ga
= aux
;
160 sc
->sc_ic
= ga
->ga_ic
;
161 sc
->sc_address
= ga
->ga_address
;
163 callout_init(&sc
->sc_timo_ch
, 0);
164 callout_init(&sc
->sc_start_ch
, 0);
166 if (gpibregister(sc
->sc_ic
, sc
->sc_address
, ppicallback
, sc
,
168 aprint_error_dev(&sc
->sc_dev
, "can't register callback\n");
172 sc
->sc_flags
= PPIF_ALIVE
;
176 ppiopen(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
178 struct ppi_softc
*sc
;
180 sc
= device_lookup_private(&ppi_cd
, UNIT(dev
));
184 if ((sc
->sc_flags
& PPIF_ALIVE
) == 0)
187 DPRINTF(PDB_FOLLOW
, ("ppiopen(%" PRIx64
", %x): flags %x\n",
188 dev
, flags
, sc
->sc_flags
));
190 if (sc
->sc_flags
& PPIF_OPEN
)
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
);
201 ppiclose(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
203 struct ppi_softc
*sc
;
205 sc
= device_lookup_private(&ppi_cd
, UNIT(dev
));
207 DPRINTF(PDB_FOLLOW
, ("ppiclose(%" PRIx64
", %x): flags %x\n",
208 dev
, flags
, sc
->sc_flags
));
210 sc
->sc_flags
&= ~PPIF_OPEN
;
215 ppicallback(void *v
, int action
)
217 struct ppi_softc
*sc
= v
;
219 DPRINTF(PDB_FOLLOW
, ("ppicallback: v=%p, action=%d\n", v
, action
));
229 DPRINTF(PDB_FOLLOW
, ("ppicallback: unknown action %d\n",
239 struct ppi_softc
*sc
= v
;
241 DPRINTF(PDB_FOLLOW
, ("ppistart(%x)\n", device_unit(&sc
->sc_dev
)));
243 sc
->sc_flags
&= ~PPIF_DELAY
;
250 struct ppi_softc
*sc
= arg
;
252 DPRINTF(PDB_FOLLOW
, ("ppitimo(%x)\n", device_unit(&sc
->sc_dev
)));
254 sc
->sc_flags
&= ~(PPIF_UIO
|PPIF_TIMO
);
259 ppiread(dev_t dev
, struct uio
*uio
, int flags
)
262 DPRINTF(PDB_FOLLOW
, ("ppiread(%" PRIx64
", %p)\n", dev
, uio
));
264 return (ppirw(dev
, uio
));
268 ppiwrite(dev_t dev
, struct uio
*uio
, int flags
)
271 DPRINTF(PDB_FOLLOW
, ("ppiwrite(%" PRIx64
", %p)\n", dev
, uio
));
273 return (ppirw(dev
, uio
));
277 ppirw(dev_t dev
, struct uio
*uio
)
279 struct ppi_softc
*sc
= device_lookup_private(&ppi_cd
, UNIT(dev
));
280 int s1
, s2
, len
, cnt
;
282 int error
= 0, gotdata
= 0;
286 if (uio
->uio_resid
== 0)
289 address
= sc
->sc_address
;
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
));
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
);
304 while (uio
->uio_resid
> 0) {
305 len
= min(buflen
, uio
->uio_resid
);
307 if (uio
->uio_rw
== UIO_WRITE
) {
308 error
= uiomove(cp
, len
, uio
);
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);
320 * Check if we timed out during sleep or uiomove
323 if ((sc
->sc_flags
& PPIF_UIO
) == 0) {
325 ("ppirw: uiomove/sleep timo, flags %x\n",
327 if (sc
->sc_flags
& PPIF_TIMO
) {
328 callout_stop(&sc
->sc_timo_ch
);
329 sc
->sc_flags
&= ~PPIF_TIMO
;
336 * Perform the operation
338 if (uio
->uio_rw
== UIO_WRITE
)
339 cnt
= gpibsend(sc
->sc_ic
, address
, sc
->sc_sec
,
342 cnt
= gpibrecv(sc
->sc_ic
, address
, sc
->sc_sec
,
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
));
350 if (uio
->uio_rw
== UIO_READ
) {
352 error
= uiomove(cp
, cnt
, uio
);
358 * Didn't get anything this time, but did in the past.
366 * Operation timeout (or non-blocking), quit now.
368 if ((sc
->sc_flags
& PPIF_UIO
) == 0) {
369 DPRINTF(PDB_IO
, ("ppirw: timeout/done\n"));
374 * Implement inter-read delay
376 if (sc
->sc_delay
> 0) {
377 sc
->sc_flags
|= PPIF_DELAY
;
378 callout_reset(&sc
->sc_start_ch
, sc
->sc_delay
,
380 error
= tsleep(sc
, (PCATCH
|PZERO
) + 1, "gpib", 0);
388 * Must not call uiomove again til we've used all data
389 * that we already grabbed.
391 if (uio
->uio_rw
== UIO_WRITE
&& cnt
!= len
) {
399 if (sc
->sc_flags
& PPIF_TIMO
) {
400 callout_stop(&sc
->sc_timo_ch
);
401 sc
->sc_flags
&= ~PPIF_TIMO
;
403 if (sc
->sc_flags
& PPIF_DELAY
) {
404 callout_stop(&sc
->sc_start_ch
);
405 sc
->sc_flags
&= ~PPIF_DELAY
;
409 * Adjust for those chars that we uiomove'ed but never wrote
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",
417 DPRINTF(PDB_FOLLOW
|PDB_IO
, ("ppirw: return %d, resid %d\n",
418 error
, uio
->uio_resid
));
423 ppiioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
425 struct ppi_softc
*sc
= device_lookup_private(&ppi_cd
, UNIT(dev
));
426 struct ppiparam
*pp
, *upp
;
432 upp
= (struct ppiparam
*)data
;
433 upp
->burst
= pp
->burst
;
434 upp
->timo
= ppihztoms(pp
->timo
);
435 upp
->delay
= ppihztoms(pp
->delay
);
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
)
443 pp
->burst
= upp
->burst
;
444 pp
->timo
= ppimstohz(upp
->timo
);
445 pp
->delay
= ppimstohz(upp
->delay
);
448 sc
->sc_sec
= *(int *)data
;