Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / amiga / dev / par.c
blob5ff16163772a40938f2f27d3f016c04eaeef6e3e
1 /* $NetBSD: par.c,v 1.36 2007/10/17 19:53:17 garbled Exp $ */
3 /*
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
29 * SUCH DAMAGE.
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
41 #include "par.h"
42 #if NPAR > 0
44 #include <sys/param.h>
45 #include <sys/errno.h>
46 #include <sys/uio.h>
47 #include <sys/device.h>
48 #include <sys/malloc.h>
49 #include <sys/file.h>
50 #include <sys/systm.h>
51 #include <sys/callout.h>
52 #include <sys/proc.h>
53 #include <sys/conf.h>
55 #include <amiga/amiga/device.h>
56 #include <amiga/amiga/cia.h>
57 #include <amiga/dev/parioctl.h>
59 struct par_softc {
60 struct device sc_dev;
62 int sc_flags;
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;
70 } *par_softcp;
72 #define getparsp(x) (x > 0 ? NULL : par_softcp)
74 /* sc_flags values */
75 #define PARF_ALIVE 0x01
76 #define PARF_OPEN 0x02
77 #define PARF_UIO 0x04
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)
85 #ifdef DEBUG
86 int pardebug = 0;
87 #define PDB_FOLLOW 0x01
88 #define PDB_IO 0x02
89 #define PDB_INTERRUPT 0x04
90 #define PDB_NOCHECK 0x80
91 #endif
93 int parrw(dev_t, struct uio *);
94 int parhztoms(int);
95 int parmstohz(int);
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,
121 /*ARGSUSED*/
123 parmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
125 static int par_found = 0;
127 if (!matchname((char *)auxp, "par") || par_found)
128 return(0);
130 par_found = 1;
131 return(1);
134 void
135 parattach(struct device *pdp, struct device *dp, void *auxp)
137 par_softcp = (struct par_softc *)dp;
139 #ifdef DEBUG
140 if ((pardebug & PDB_NOCHECK) == 0)
141 #endif
142 par_softcp->sc_flags = PARF_ALIVE;
143 printf("\n");
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)
156 return(ENXIO);
157 #ifdef DEBUG
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)));
164 #endif
165 if (sc->sc_flags & PARF_OPEN)
166 return(EBUSY);
167 /* can either read or write, but not both */
168 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE))
169 return EINVAL;
171 sc->sc_flags |= PARF_OPEN;
173 if (flags & FREAD)
174 sc->sc_flags |= PARF_OREAD;
175 else
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;
183 return(0);
187 parclose(dev_t dev, int flags, int mode, struct lwp *l)
189 int unit = UNIT(dev);
190 struct par_softc *sc = getparsp(unit);
192 #ifdef DEBUG
193 if (pardebug & PDB_FOLLOW)
194 printf("parclose(%llx, %x): flags %x\n",
195 dev, flags, sc->sc_flags);
196 #endif
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;
200 return(0);
203 void
204 parstart(void *arg)
206 struct par_softc *sc = arg;
208 #ifdef DEBUG
209 if (pardebug & PDB_FOLLOW)
210 printf("parstart(%x)\n", device_unit(&sc->sc_dev));
211 #endif
212 sc->sc_flags &= ~PARF_DELAY;
213 wakeup(sc);
216 void
217 partimo(void *arg)
219 struct par_softc *sc = arg;
221 #ifdef DEBUG
222 if (pardebug & PDB_FOLLOW)
223 printf("partimo(%x)\n", device_unit(&sc->sc_dev));
224 #endif
225 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
226 wakeup(sc);
230 parread(dev_t dev, struct uio *uio, int flags)
233 #ifdef DEBUG
234 if (pardebug & PDB_FOLLOW)
235 printf("parread(%llx, %p)\n", dev, uio);
236 #endif
237 return (parrw(dev, uio));
242 parwrite(dev_t dev, struct uio *uio, int flags)
245 #ifdef DEBUG
246 if (pardebug & PDB_FOLLOW)
247 printf("parwrite(%llx, %p)\n", dev, uio);
248 #endif
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;
259 register char *cp;
260 int error = 0, gotdata = 0;
261 int buflen;
262 char *buf;
264 len = 0;
265 cnt = 0;
266 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
267 return EINVAL;
269 if (uio->uio_resid == 0)
270 return(0);
272 #ifdef DEBUG
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);
277 #endif
278 buflen = min(sc->sc_burst, uio->uio_resid);
279 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
280 sc->sc_flags |= PARF_UIO;
281 if (sc->sc_timo > 0)
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);
289 cp = buf;
290 if (uio->uio_rw == UIO_WRITE)
292 error = uiomove(cp, len, uio);
293 if (error)
294 break;
296 again:
297 #if 0
298 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0)
299 sleep(sc, PRIBIO+1);
300 #endif
302 * Check if we timed out during sleep or uiomove
304 s = splsoftclock();
305 if ((sc->sc_flags & PARF_UIO) == 0)
307 #ifdef DEBUG
308 if (pardebug & PDB_IO)
309 printf("parrw: uiomove/sleep timo, flags %x\n",
310 sc->sc_flags);
311 #endif
312 if (sc->sc_flags & PARF_TIMO)
314 callout_stop(&sc->sc_timo_ch);
315 sc->sc_flags &= ~PARF_TIMO;
317 splx(s);
318 break;
320 splx(s);
322 * Perform the operation
324 if (uio->uio_rw == UIO_WRITE)
325 cnt = parsend (cp, len);
326 else
327 cnt = parreceive (cp, len);
329 if (cnt < 0)
331 error = -cnt;
332 break;
335 s = splbio();
336 #if 0
337 hpibfree(&sc->sc_dq);
338 #endif
339 #ifdef DEBUG
340 if (pardebug & PDB_IO)
341 printf("parrw: %s(%p, %d) -> %d\n",
342 uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt);
343 #endif
344 splx(s);
345 if (uio->uio_rw == UIO_READ)
347 if (cnt)
349 error = uiomove(cp, cnt, uio);
350 if (error)
351 break;
352 gotdata++;
355 * Didn't get anything this time, but did in the past.
356 * Consider us done.
358 else if (gotdata)
359 break;
361 s = splsoftclock();
363 * Operation timeout (or non-blocking), quit now.
365 if ((sc->sc_flags & PARF_UIO) == 0)
367 #ifdef DEBUG
368 if (pardebug & PDB_IO)
369 printf("parrw: timeout/done\n");
370 #endif
371 splx(s);
372 break;
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);
382 if (error)
384 splx(s);
385 break;
388 splx(s);
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)
395 cp += cnt;
396 len -= cnt;
397 cnt = 0;
398 goto again;
401 s = splsoftclock();
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;
412 splx(s);
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);
419 #ifdef DEBUG
420 if (pardebug & PDB_IO)
421 printf("parrw: short write, adjust by %d\n",
422 len-cnt);
423 #endif
425 free(buf, M_DEVBUF);
426 #ifdef DEBUG
427 if (pardebug & (PDB_FOLLOW|PDB_IO))
428 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
429 #endif
430 return (error);
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;
438 int error = 0;
440 switch (cmd)
442 case PARIOCGPARAM:
443 pp = &sc->sc_param;
444 upp = (struct parparam *)data;
445 upp->burst = pp->burst;
446 upp->timo = parhztoms(pp->timo);
447 upp->delay = parhztoms(pp->delay);
448 break;
450 case PARIOCSPARAM:
451 pp = &sc->sc_param;
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)
455 return(EINVAL);
456 pp->burst = upp->burst;
457 pp->timo = parmstohz(upp->timo);
458 pp->delay = parmstohz(upp->delay);
459 break;
461 default:
462 return(EINVAL);
464 return (error);
468 parhztoms(int h)
470 extern int hz;
471 register int m = h;
473 if (m > 0)
474 m = m * 1000 / hz;
475 return(m);
479 parmstohz(int m)
481 extern int hz;
482 register int h = m;
484 if (h > 0) {
485 h = h * hz / 1000;
486 if (h == 0)
487 h = 1000 / hz;
489 return(h);
492 /* stuff below here if for interrupt driven output of data thru
493 the parallel port. */
495 int parsend_pending;
497 void
498 parintr(void *arg)
500 int s;
502 s = splclock();
504 #ifdef DEBUG
505 if (pardebug & PDB_INTERRUPT)
506 printf("parintr\n");
507 #endif
508 parsend_pending = 0;
510 wakeup(parintr);
511 splx(s);
515 parsendch (u_char ch)
517 int error = 0;
518 int s;
520 /* if either offline, busy or out of paper, wait for that
521 condition to clear */
522 s = splclock();
523 while (!error
524 && (parsend_pending
525 || ((ciab.pra ^ CIAB_PRA_SEL)
526 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))))
528 extern int hz;
530 #ifdef DEBUG
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)));
535 #endif
536 /* this is essentially a flipflop to have us wait for the
537 first character being transmitted when trying to transmit
538 the second, etc. */
539 parsend_pending = 0;
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)
545 error = 0;
546 if (error > 0)
548 #ifdef DEBUG
549 if (pardebug & PDB_INTERRUPT)
550 printf ("parsendch interrupted, error = %d\n", error);
551 #endif
555 if (! error)
557 #ifdef DEBUG
558 if (pardebug & PDB_INTERRUPT)
559 printf ("#%d", ch);
560 #endif
561 ciaa.prb = ch;
562 parsend_pending = 1;
565 splx (s);
567 return error;
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 */
581 ciaa.ddrb = 0xff;
583 for (; len; len--, buf++)
584 if ((err = parsendch (*buf)) != 0)
585 return err < 0 ? -EINTR : -err;
587 /* either all or nothing.. */
588 return orig_len;
594 parreceive (u_char *buf, int len)
596 /* oh deary me, something's gotta be left to be implemented
597 later... */
598 return 0;
602 #endif