1 /* $NetBSD: par.c,v 1.36 2008/06/08 16:39:11 tsutsui Exp $ */
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)ppi.c 7.3 (Berkeley) 12/16/90
35 * parallel port interface
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: par.c,v 1.36 2008/06/08 16:39:11 tsutsui Exp $");
41 #include <sys/param.h>
42 #include <sys/errno.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
47 #include <sys/systm.h>
48 #include <sys/callout.h>
51 #include <sys/kernel.h>
53 #include <machine/bus.h>
54 #include <machine/cpu.h>
55 #include <machine/parioctl.h>
57 #include <arch/x68k/dev/intiovar.h>
62 bus_space_tag_t sc_bst
;
63 bus_space_handle_t sc_bsh
;
65 struct parparam sc_param
;
66 #define sc_burst sc_param.burst
67 #define sc_timo sc_param.timo
68 #define sc_delay sc_param.delay
69 struct callout sc_timo_ch
;
70 struct callout sc_start_ch
;
78 #define PARF_ALIVE 0x01
79 #define PARF_OPEN 0x02
81 #define PARF_TIMO 0x08
82 #define PARF_DELAY 0x10
83 #define PARF_OREAD 0x40 /* no support */
84 #define PARF_OWRITE 0x80
88 void parstart(void *);
90 int parrw(dev_t
, struct uio
*);
93 int parsendch(struct par_softc
*, u_char
);
94 int parsend(struct par_softc
*, u_char
*, int);
96 static struct callout intr_callout
;
98 #define UNIT(x) minor(x)
101 #define PDB_FOLLOW 0x01
103 #define PDB_INTERRUPT 0x04
104 #define PDB_NOCHECK 0x80
106 int pardebug
= PDB_FOLLOW
| PDB_IO
| PDB_INTERRUPT
;
112 int parmatch(device_t
, cfdata_t
, void *);
113 void parattach(device_t
, device_t
, void *);
115 CFATTACH_DECL_NEW(par
, sizeof(struct par_softc
),
116 parmatch
, parattach
, NULL
, NULL
);
118 extern struct cfdriver par_cd
;
120 static int par_attached
;
122 dev_type_open(paropen
);
123 dev_type_close(parclose
);
124 dev_type_write(parwrite
);
125 dev_type_ioctl(parioctl
);
127 const struct cdevsw par_cdevsw
= {
128 paropen
, parclose
, noread
, parwrite
, parioctl
,
129 nostop
, notty
, nopoll
, nommap
, nokqfilter
,
133 parmatch(device_t pdp
, cfdata_t cfp
, void *aux
)
135 struct intio_attach_args
*ia
= aux
;
137 /* X680x0 has only one parallel port */
138 if (strcmp(ia
->ia_name
, "par") || par_attached
)
141 if (ia
->ia_addr
== INTIOCF_ADDR_DEFAULT
)
142 ia
->ia_addr
= 0xe8c000;
143 ia
->ia_size
= 0x2000;
144 if (intio_map_allocate_region(pdp
, ia
, INTIO_MAP_TESTONLY
))
146 if (ia
->ia_intr
== INTIOCF_INTR_DEFAULT
)
149 if (ia
->ia_intr
!= 99)
157 parattach(device_t pdp
, device_t dp
, void *aux
)
159 struct par_softc
*sc
= device_private(dp
);
160 struct intio_attach_args
*ia
= aux
;
166 sc
->sc_flags
= PARF_ALIVE
;
167 aprint_normal(": parallel port (write only, interrupt)\n");
168 ia
->ia_size
= 0x2000;
169 r
= intio_map_allocate_region(pdp
, ia
, INTIO_MAP_ALLOCATE
);
172 panic("IO map for PAR corruption??");
174 sc
->sc_bst
= ia
->ia_bst
;
175 r
= bus_space_map(sc
->sc_bst
,
176 ia
->ia_addr
, ia
->ia_size
,
177 BUS_SPACE_MAP_SHIFTED
,
181 panic("Cannot map IO space for PAR.");
184 intio_set_sicilian_intr(intio_get_sicilian_intr() &
187 intio_intr_establish(ia
->ia_intr
, "par",
188 (intio_intr_handler_t
)parintr
, (void *)1);
190 callout_init(&sc
->sc_timo_ch
, 0);
191 callout_init(&sc
->sc_start_ch
, 0);
192 callout_init(&intr_callout
, 0);
196 paropen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
198 int unit
= UNIT(dev
);
199 struct par_softc
*sc
;
201 sc
= device_lookup_private(&par_cd
, unit
);
202 if (sc
== NULL
|| !(sc
->sc_flags
& PARF_ALIVE
))
204 if (sc
->sc_flags
& PARF_OPEN
)
206 /* X680x0 can't read */
207 if ((flags
& FREAD
) == FREAD
)
210 sc
->sc_flags
|= PARF_OPEN
;
212 sc
->sc_flags
|= PARF_OWRITE
;
214 sc
->sc_burst
= PAR_BURST
;
215 sc
->sc_timo
= parmstohz(PAR_TIMO
);
216 sc
->sc_delay
= parmstohz(PAR_DELAY
);
222 parclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
224 int unit
= UNIT(dev
);
226 struct par_softc
*sc
= device_lookup_private(&par_cd
, unit
);
228 sc
->sc_flags
&= ~(PARF_OPEN
|PARF_OWRITE
);
230 /* don't allow interrupts any longer */
232 intio_set_sicilian_intr(intio_get_sicilian_intr() &
242 struct par_softc
*sc
= arg
;
244 if (pardebug
& PDB_FOLLOW
)
245 printf("parstart(%x)\n", device_unit(sc
->sc_dev
));
247 sc
->sc_flags
&= ~PARF_DELAY
;
254 struct par_softc
*sc
= arg
;
256 if (pardebug
& PDB_FOLLOW
)
257 printf("partimo(%x)\n", device_unit(sc
->sc_dev
));
259 sc
->sc_flags
&= ~(PARF_UIO
|PARF_TIMO
);
264 parwrite(dev_t dev
, struct uio
*uio
, int flag
)
268 if (pardebug
& PDB_FOLLOW
)
269 printf("parwrite(%x, %p)\n", dev
, uio
);
271 return (parrw(dev
, uio
));
275 parrw(dev_t dev
, struct uio
*uio
)
277 int unit
= UNIT(dev
);
278 struct par_softc
*sc
= device_lookup_private(&par_cd
, unit
);
279 int len
=0xdeadbeef; /* XXX: shutup gcc */
286 if (!!(sc
->sc_flags
& PARF_OREAD
) ^ (uio
->uio_rw
== UIO_READ
))
289 if (uio
->uio_resid
== 0)
292 buflen
= min(sc
->sc_burst
, uio
->uio_resid
);
293 buf
= (char *)malloc(buflen
, M_DEVBUF
, M_WAITOK
);
294 sc
->sc_flags
|= PARF_UIO
;
295 if (sc
->sc_timo
> 0) {
296 sc
->sc_flags
|= PARF_TIMO
;
297 callout_reset(&sc
->sc_timo_ch
, sc
->sc_timo
, partimo
, sc
);
299 while (uio
->uio_resid
> 0) {
300 len
= min(buflen
, uio
->uio_resid
);
302 if (uio
->uio_rw
== UIO_WRITE
) {
303 error
= uiomove(cp
, len
, uio
);
310 * Check if we timed out during sleep or uiomove
312 if ((sc
->sc_flags
& PARF_UIO
) == 0) {
314 if (pardebug
& PDB_IO
)
315 printf("parrw: uiomove/sleep timo, flags %x\n",
318 if (sc
->sc_flags
& PARF_TIMO
) {
319 callout_stop(&sc
->sc_timo_ch
);
320 sc
->sc_flags
&= ~PARF_TIMO
;
327 * Perform the operation
329 cnt
= parsend(sc
, cp
, len
);
337 * Operation timeout (or non-blocking), quit now.
339 if ((sc
->sc_flags
& PARF_UIO
) == 0) {
341 if (pardebug
& PDB_IO
)
342 printf("parrw: timeout/done\n");
348 * Implement inter-read delay
350 if (sc
->sc_delay
> 0) {
351 sc
->sc_flags
|= PARF_DELAY
;
352 callout_reset(&sc
->sc_start_ch
, sc
->sc_delay
,
354 error
= tsleep(sc
, PCATCH
|(PZERO
-1), "par-cdelay", 0);
362 * Must not call uiomove again til we've used all data
363 * that we already grabbed.
365 if (uio
->uio_rw
== UIO_WRITE
&& cnt
!= len
) {
373 if (sc
->sc_flags
& PARF_TIMO
) {
374 callout_stop(&sc
->sc_timo_ch
);
375 sc
->sc_flags
&= ~PARF_TIMO
;
377 if (sc
->sc_flags
& PARF_DELAY
) {
378 callout_stop(&sc
->sc_start_ch
);
379 sc
->sc_flags
&= ~PARF_DELAY
;
383 * Adjust for those chars that we uiomove'ed but never wrote
386 * XXXjdolecek: this len usage is wrong, this will be incorrect
387 * if the transfer size is longer than sc_burst
389 if (uio
->uio_rw
== UIO_WRITE
&& cnt
!= len
) {
390 uio
->uio_resid
+= (len
- cnt
);
392 if (pardebug
& PDB_IO
)
393 printf("parrw: short write, adjust by %d\n",
399 if (pardebug
& (PDB_FOLLOW
|PDB_IO
))
400 printf("parrw: return %d, resid %d\n", error
, uio
->uio_resid
);
406 parioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
408 struct par_softc
*sc
= device_lookup_private(&par_cd
, UNIT(dev
));
409 struct parparam
*pp
, *upp
;
415 upp
= (struct parparam
*)data
;
416 upp
->burst
= pp
->burst
;
417 upp
->timo
= parhztoms(pp
->timo
);
418 upp
->delay
= parhztoms(pp
->delay
);
423 upp
= (struct parparam
*)data
;
424 if (upp
->burst
< PAR_BURST_MIN
|| upp
->burst
> PAR_BURST_MAX
||
425 upp
->delay
< PAR_DELAY_MIN
|| upp
->delay
> PAR_DELAY_MAX
)
427 pp
->burst
= upp
->burst
;
428 pp
->timo
= parmstohz(upp
->timo
);
429 pp
->delay
= parmstohz(upp
->delay
);
461 /* stuff below here if for interrupt driven output of data thru
462 the parallel port. */
464 int partimeout_pending
;
475 intio_set_sicilian_intr(intio_get_sicilian_intr() &
479 if (pardebug
& PDB_INTERRUPT
)
480 printf("parintr %d(%s)\n", mask
, mask
? "FLG" : "tout");
482 /* if invoked from timeout handler, mask will be 0,
483 * if from interrupt, it will contain the cia-icr mask,
487 if (partimeout_pending
)
488 callout_stop(&intr_callout
);
493 /* either way, there won't be a timeout pending any longer */
494 partimeout_pending
= 0;
501 parsendch(struct par_softc
*sc
, u_char ch
)
506 /* if either offline, busy or out of paper, wait for that
507 condition to clear */
511 || !(intio_get_sicilian_intr() & SICILIAN_STAT_PAR
)))
513 /* wait a second, and try again */
514 callout_reset(&intr_callout
, hz
, parintr
, 0);
515 partimeout_pending
= 1;
516 /* this is essentially a flipflop to have us wait for the
517 first character being transmitted when trying to transmit
520 /* it's quite important that a parallel putc can be
521 interrupted, given the possibility to lock a printer
522 in an offline condition.. */
523 if ((error
= tsleep(parintr
, PCATCH
|(PZERO
-1), "parsendch", 0))) {
525 if (pardebug
& PDB_INTERRUPT
)
526 printf("parsendch interrupted, error = %d\n", error
);
528 if (partimeout_pending
)
529 callout_stop(&intr_callout
);
531 partimeout_pending
= 0;
537 if (pardebug
& PDB_INTERRUPT
)
540 bus_space_write_1(sc
->sc_bst
, sc
->sc_bsh
, PAR_DATA
, ch
);
541 DELAY(1); /* (DELAY(1) == 1us) > 0.5us */
542 bus_space_write_1(sc
->sc_bst
, sc
->sc_bsh
, PAR_STROBE
, 0);
543 intio_set_sicilian_intr(intio_get_sicilian_intr() |
546 bus_space_write_1(sc
->sc_bst
, sc
->sc_bsh
, PAR_STROBE
, 1);
557 parsend(struct par_softc
*sc
, u_char
*buf
, int len
)
559 int err
, orig_len
= len
;
561 for (; len
; len
--, buf
++)
562 if ((err
= parsendch(sc
, *buf
)))
563 return err
< 0 ? -EINTR
: -err
;
565 /* either all or nothing.. */