1 /* $NetBSD: par.c,v 1.36 2007/10/17 19:53:17 garbled 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
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: par.c,v 1.36 2007/10/17 19:53:17 garbled Exp $");
38 * parallel port interface
44 #include <sys/param.h>
45 #include <sys/errno.h>
47 #include <sys/device.h>
48 #include <sys/malloc.h>
50 #include <sys/systm.h>
51 #include <sys/callout.h>
55 #include <amiga/amiga/device.h>
56 #include <amiga/amiga/cia.h>
57 #include <amiga/dev/parioctl.h>
63 struct parparam sc_param
;
64 #define sc_burst sc_param.burst
65 #define sc_timo sc_param.timo
66 #define sc_delay sc_param.delay
68 struct callout sc_timo_ch
;
69 struct callout sc_start_ch
;
72 #define getparsp(x) (x > 0 ? NULL : par_softcp)
75 #define PARF_ALIVE 0x01
76 #define PARF_OPEN 0x02
78 #define PARF_TIMO 0x08
79 #define PARF_DELAY 0x10
80 #define PARF_OREAD 0x40
81 #define PARF_OWRITE 0x80
83 #define UNIT(x) minor(x)
87 #define PDB_FOLLOW 0x01
89 #define PDB_INTERRUPT 0x04
90 #define PDB_NOCHECK 0x80
93 int parrw(dev_t
, struct uio
*);
96 int parsend(u_char
*, int);
97 int parreceive(u_char
*, int);
98 int parsendch(u_char
);
100 void partimo(void *);
101 void parstart(void *);
102 void parintr(void *);
104 void parattach(struct device
*, struct device
*, void *);
105 int parmatch(struct device
*, struct cfdata
*, void *);
107 CFATTACH_DECL(par
, sizeof(struct par_softc
),
108 parmatch
, parattach
, NULL
, NULL
);
110 dev_type_open(paropen
);
111 dev_type_close(parclose
);
112 dev_type_read(parread
);
113 dev_type_write(parwrite
);
114 dev_type_ioctl(parioctl
);
116 const struct cdevsw par_cdevsw
= {
117 paropen
, parclose
, parread
, parwrite
, parioctl
,
118 nostop
, notty
, nopoll
, nommap
, nokqfilter
,
123 parmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
125 static int par_found
= 0;
127 if (!matchname((char *)auxp
, "par") || par_found
)
135 parattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
137 par_softcp
= (struct par_softc
*)dp
;
140 if ((pardebug
& PDB_NOCHECK
) == 0)
142 par_softcp
->sc_flags
= PARF_ALIVE
;
145 callout_init(&par_softcp
->sc_timo_ch
, 0);
146 callout_init(&par_softcp
->sc_start_ch
, 0);
150 paropen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
152 int unit
= UNIT(dev
);
153 struct par_softc
*sc
= getparsp(unit
);
155 if (unit
>= NPAR
|| (sc
->sc_flags
& PARF_ALIVE
) == 0)
158 if (pardebug
& PDB_FOLLOW
) {
159 printf("paropen(%llx, %x): flags %x, ",
160 dev
, flags
, sc
->sc_flags
);
161 printf ("port = $%x\n", ((ciab
.pra
^ CIAB_PRA_SEL
)
162 & (CIAB_PRA_SEL
|CIAB_PRA_BUSY
|CIAB_PRA_POUT
)));
165 if (sc
->sc_flags
& PARF_OPEN
)
167 /* can either read or write, but not both */
168 if ((flags
& (FREAD
|FWRITE
)) == (FREAD
|FWRITE
))
171 sc
->sc_flags
|= PARF_OPEN
;
174 sc
->sc_flags
|= PARF_OREAD
;
176 sc
->sc_flags
|= PARF_OWRITE
;
178 sc
->sc_burst
= PAR_BURST
;
179 sc
->sc_timo
= parmstohz(PAR_TIMO
);
180 sc
->sc_delay
= parmstohz(PAR_DELAY
);
181 /* enable interrupts for CIAA-FLG */
182 ciaa
.icr
= CIA_ICR_IR_SC
| CIA_ICR_FLG
;
187 parclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
189 int unit
= UNIT(dev
);
190 struct par_softc
*sc
= getparsp(unit
);
193 if (pardebug
& PDB_FOLLOW
)
194 printf("parclose(%llx, %x): flags %x\n",
195 dev
, flags
, sc
->sc_flags
);
197 sc
->sc_flags
&= ~(PARF_OPEN
|PARF_OREAD
|PARF_OWRITE
);
198 /* don't allow interrupts for CIAA-FLG any longer */
199 ciaa
.icr
= CIA_ICR_FLG
;
206 struct par_softc
*sc
= arg
;
209 if (pardebug
& PDB_FOLLOW
)
210 printf("parstart(%x)\n", device_unit(&sc
->sc_dev
));
212 sc
->sc_flags
&= ~PARF_DELAY
;
219 struct par_softc
*sc
= arg
;
222 if (pardebug
& PDB_FOLLOW
)
223 printf("partimo(%x)\n", device_unit(&sc
->sc_dev
));
225 sc
->sc_flags
&= ~(PARF_UIO
|PARF_TIMO
);
230 parread(dev_t dev
, struct uio
*uio
, int flags
)
234 if (pardebug
& PDB_FOLLOW
)
235 printf("parread(%llx, %p)\n", dev
, uio
);
237 return (parrw(dev
, uio
));
242 parwrite(dev_t dev
, struct uio
*uio
, int flags
)
246 if (pardebug
& PDB_FOLLOW
)
247 printf("parwrite(%llx, %p)\n", dev
, uio
);
249 return (parrw(dev
, uio
));
254 parrw(dev_t dev
, register struct uio
*uio
)
256 int unit
= UNIT(dev
);
257 register struct par_softc
*sc
= getparsp(unit
);
258 register int s
, len
, cnt
;
260 int error
= 0, gotdata
= 0;
266 if (!!(sc
->sc_flags
& PARF_OREAD
) ^ (uio
->uio_rw
== UIO_READ
))
269 if (uio
->uio_resid
== 0)
273 if (pardebug
& (PDB_FOLLOW
|PDB_IO
))
274 printf("parrw(%llx, %p, %c): burst %d, timo %d, resid %x\n",
275 dev
, uio
, uio
->uio_rw
== UIO_READ
? 'R' : 'W',
276 sc
->sc_burst
, sc
->sc_timo
, uio
->uio_resid
);
278 buflen
= min(sc
->sc_burst
, uio
->uio_resid
);
279 buf
= (char *)malloc(buflen
, M_DEVBUF
, M_WAITOK
);
280 sc
->sc_flags
|= PARF_UIO
;
283 sc
->sc_flags
|= PARF_TIMO
;
284 callout_reset(&sc
->sc_timo_ch
, sc
->sc_timo
, partimo
, sc
);
286 while (uio
->uio_resid
> 0)
288 len
= min(buflen
, uio
->uio_resid
);
290 if (uio
->uio_rw
== UIO_WRITE
)
292 error
= uiomove(cp
, len
, uio
);
298 if ((sc
->sc_flags
& PARF_UIO
) && hpibreq(&sc
->sc_dq
) == 0)
302 * Check if we timed out during sleep or uiomove
305 if ((sc
->sc_flags
& PARF_UIO
) == 0)
308 if (pardebug
& PDB_IO
)
309 printf("parrw: uiomove/sleep timo, flags %x\n",
312 if (sc
->sc_flags
& PARF_TIMO
)
314 callout_stop(&sc
->sc_timo_ch
);
315 sc
->sc_flags
&= ~PARF_TIMO
;
322 * Perform the operation
324 if (uio
->uio_rw
== UIO_WRITE
)
325 cnt
= parsend (cp
, len
);
327 cnt
= parreceive (cp
, len
);
337 hpibfree(&sc
->sc_dq
);
340 if (pardebug
& PDB_IO
)
341 printf("parrw: %s(%p, %d) -> %d\n",
342 uio
->uio_rw
== UIO_READ
? "recv" : "send", cp
, len
, cnt
);
345 if (uio
->uio_rw
== UIO_READ
)
349 error
= uiomove(cp
, cnt
, uio
);
355 * Didn't get anything this time, but did in the past.
363 * Operation timeout (or non-blocking), quit now.
365 if ((sc
->sc_flags
& PARF_UIO
) == 0)
368 if (pardebug
& PDB_IO
)
369 printf("parrw: timeout/done\n");
375 * Implement inter-read delay
377 if (sc
->sc_delay
> 0)
379 sc
->sc_flags
|= PARF_DELAY
;
380 callout_reset(&sc
->sc_start_ch
, sc
->sc_delay
, parstart
, sc
);
381 error
= tsleep(sc
, PCATCH
| (PZERO
- 1), "par-cdelay", 0);
390 * Must not call uiomove again til we've used all data
391 * that we already grabbed.
393 if (uio
->uio_rw
== UIO_WRITE
&& cnt
!= len
)
402 if (sc
->sc_flags
& PARF_TIMO
)
404 callout_stop(&sc
->sc_timo_ch
);
405 sc
->sc_flags
&= ~PARF_TIMO
;
407 if (sc
->sc_flags
& PARF_DELAY
)
409 callout_stop(&sc
->sc_start_ch
);
410 sc
->sc_flags
&= ~PARF_DELAY
;
414 * Adjust for those chars that we uiomove'ed but never wrote
416 if (uio
->uio_rw
== UIO_WRITE
&& cnt
!= len
)
418 uio
->uio_resid
+= (len
- cnt
);
420 if (pardebug
& PDB_IO
)
421 printf("parrw: short write, adjust by %d\n",
427 if (pardebug
& (PDB_FOLLOW
|PDB_IO
))
428 printf("parrw: return %d, resid %d\n", error
, uio
->uio_resid
);
434 parioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
436 struct par_softc
*sc
= getparsp(UNIT(dev
));
437 struct parparam
*pp
, *upp
;
444 upp
= (struct parparam
*)data
;
445 upp
->burst
= pp
->burst
;
446 upp
->timo
= parhztoms(pp
->timo
);
447 upp
->delay
= parhztoms(pp
->delay
);
452 upp
= (struct parparam
*)data
;
453 if (upp
->burst
< PAR_BURST_MIN
|| upp
->burst
> PAR_BURST_MAX
||
454 upp
->delay
< PAR_DELAY_MIN
|| upp
->delay
> PAR_DELAY_MAX
)
456 pp
->burst
= upp
->burst
;
457 pp
->timo
= parmstohz(upp
->timo
);
458 pp
->delay
= parmstohz(upp
->delay
);
492 /* stuff below here if for interrupt driven output of data thru
493 the parallel port. */
505 if (pardebug
& PDB_INTERRUPT
)
515 parsendch (u_char ch
)
520 /* if either offline, busy or out of paper, wait for that
521 condition to clear */
525 || ((ciab
.pra
^ CIAB_PRA_SEL
)
526 & (CIAB_PRA_SEL
|CIAB_PRA_BUSY
|CIAB_PRA_POUT
))))
531 if (pardebug
& PDB_INTERRUPT
)
532 printf ("parsendch, port = $%x\n",
533 ((ciab
.pra
^ CIAB_PRA_SEL
)
534 & (CIAB_PRA_SEL
|CIAB_PRA_BUSY
|CIAB_PRA_POUT
)));
536 /* this is essentially a flipflop to have us wait for the
537 first character being transmitted when trying to transmit
540 /* it's quite important that a parallel putc can be
541 interrupted, given the possibility to lock a printer
542 in an offline condition.. */
543 error
= tsleep(parintr
, PCATCH
| (PZERO
- 1), "parsendch", hz
);
544 if (error
== EWOULDBLOCK
)
549 if (pardebug
& PDB_INTERRUPT
)
550 printf ("parsendch interrupted, error = %d\n", error
);
558 if (pardebug
& PDB_INTERRUPT
)
572 parsend (u_char
*buf
, int len
)
574 int err
, orig_len
= len
;
576 /* make sure I/O lines are setup right for output */
578 /* control lines set to input */
579 ciab
.ddra
&= ~(CIAB_PRA_SEL
|CIAB_PRA_POUT
|CIAB_PRA_BUSY
);
580 /* data lines to output */
583 for (; len
; len
--, buf
++)
584 if ((err
= parsendch (*buf
)) != 0)
585 return err
< 0 ? -EINTR
: -err
;
587 /* either all or nothing.. */
594 parreceive (u_char
*buf
, int len
)
596 /* oh deary me, something's gotta be left to be implemented