Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / x68k / dev / par.c
blobc4d1fc497819d6dbeeb5ef15c03f34372c76b705
1 /* $NetBSD: par.c,v 1.36 2008/06/08 16:39:11 tsutsui 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
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>
43 #include <sys/uio.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/file.h>
47 #include <sys/systm.h>
48 #include <sys/callout.h>
49 #include <sys/proc.h>
50 #include <sys/conf.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>
59 struct par_softc {
60 device_t sc_dev;
62 bus_space_tag_t sc_bst;
63 bus_space_handle_t sc_bsh;
64 int sc_flags;
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;
71 } ;
73 /* par registers */
74 #define PAR_DATA 1
75 #define PAR_STROBE 3
77 /* sc_flags values */
78 #define PARF_ALIVE 0x01
79 #define PARF_OPEN 0x02
80 #define PARF_UIO 0x04
81 #define PARF_TIMO 0x08
82 #define PARF_DELAY 0x10
83 #define PARF_OREAD 0x40 /* no support */
84 #define PARF_OWRITE 0x80
87 void partimo(void *);
88 void parstart(void *);
89 void parintr(void *);
90 int parrw(dev_t, struct uio *);
91 int parhztoms(int);
92 int parmstohz(int);
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)
100 #ifdef DEBUG
101 #define PDB_FOLLOW 0x01
102 #define PDB_IO 0x02
103 #define PDB_INTERRUPT 0x04
104 #define PDB_NOCHECK 0x80
105 #ifdef PARDEBUG
106 int pardebug = PDB_FOLLOW | PDB_IO | PDB_INTERRUPT;
107 #else
108 int pardebug = 0;
109 #endif
110 #endif
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)
139 return 0;
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))
145 return 0;
146 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
147 ia->ia_intr = 99;
148 #if DIAGNOSTIC
149 if (ia->ia_intr != 99)
150 return 0;
151 #endif
153 return 1;
156 void
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;
161 int r;
163 par_attached = 1;
165 sc->sc_dev = dp;
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);
170 #ifdef DIAGNOSTIC
171 if (r)
172 panic("IO map for PAR corruption??");
173 #endif
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,
178 &sc->sc_bsh);
179 #ifdef DIAGNOSTIC
180 if (r)
181 panic("Cannot map IO space for PAR.");
182 #endif
184 intio_set_sicilian_intr(intio_get_sicilian_intr() &
185 ~SICILIAN_INTR_PAR);
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))
203 return(ENXIO);
204 if (sc->sc_flags & PARF_OPEN)
205 return(EBUSY);
206 /* X680x0 can't read */
207 if ((flags & FREAD) == FREAD)
208 return (EINVAL);
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);
218 return(0);
222 parclose(dev_t dev, int flags, int mode, struct lwp *l)
224 int unit = UNIT(dev);
225 int s;
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 */
231 s = spl1();
232 intio_set_sicilian_intr(intio_get_sicilian_intr() &
233 ~SICILIAN_INTR_PAR);
234 splx(s);
236 return (0);
239 void
240 parstart(void *arg)
242 struct par_softc *sc = arg;
243 #ifdef DEBUG
244 if (pardebug & PDB_FOLLOW)
245 printf("parstart(%x)\n", device_unit(sc->sc_dev));
246 #endif
247 sc->sc_flags &= ~PARF_DELAY;
248 wakeup(sc);
251 void
252 partimo(void *arg)
254 struct par_softc *sc = arg;
255 #ifdef DEBUG
256 if (pardebug & PDB_FOLLOW)
257 printf("partimo(%x)\n", device_unit(sc->sc_dev));
258 #endif
259 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
260 wakeup(sc);
264 parwrite(dev_t dev, struct uio *uio, int flag)
267 #ifdef DEBUG
268 if (pardebug & PDB_FOLLOW)
269 printf("parwrite(%x, %p)\n", dev, uio);
270 #endif
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 */
280 int s, cnt=0;
281 char *cp;
282 int error = 0;
283 int buflen;
284 char *buf;
286 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
287 return EINVAL;
289 if (uio->uio_resid == 0)
290 return(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);
301 cp = buf;
302 if (uio->uio_rw == UIO_WRITE) {
303 error = uiomove(cp, len, uio);
304 if (error)
305 break;
307 again:
308 s = splsoftclock();
310 * Check if we timed out during sleep or uiomove
312 if ((sc->sc_flags & PARF_UIO) == 0) {
313 #ifdef DEBUG
314 if (pardebug & PDB_IO)
315 printf("parrw: uiomove/sleep timo, flags %x\n",
316 sc->sc_flags);
317 #endif
318 if (sc->sc_flags & PARF_TIMO) {
319 callout_stop(&sc->sc_timo_ch);
320 sc->sc_flags &= ~PARF_TIMO;
322 splx(s);
323 break;
325 splx(s);
327 * Perform the operation
329 cnt = parsend(sc, cp, len);
330 if (cnt < 0) {
331 error = -cnt;
332 break;
335 s = splsoftclock();
337 * Operation timeout (or non-blocking), quit now.
339 if ((sc->sc_flags & PARF_UIO) == 0) {
340 #ifdef DEBUG
341 if (pardebug & PDB_IO)
342 printf("parrw: timeout/done\n");
343 #endif
344 splx(s);
345 break;
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,
353 parstart, sc);
354 error = tsleep(sc, PCATCH|(PZERO-1), "par-cdelay", 0);
355 if (error) {
356 splx(s);
357 break;
360 splx(s);
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) {
366 cp += cnt;
367 len -= cnt;
368 cnt = 0;
369 goto again;
372 s = splsoftclock();
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;
381 splx(s);
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);
391 #ifdef DEBUG
392 if (pardebug & PDB_IO)
393 printf("parrw: short write, adjust by %d\n",
394 len-cnt);
395 #endif
397 free(buf, M_DEVBUF);
398 #ifdef DEBUG
399 if (pardebug & (PDB_FOLLOW|PDB_IO))
400 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
401 #endif
402 return (error);
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;
410 int error = 0;
412 switch (cmd) {
413 case PARIOCGPARAM:
414 pp = &sc->sc_param;
415 upp = (struct parparam *)data;
416 upp->burst = pp->burst;
417 upp->timo = parhztoms(pp->timo);
418 upp->delay = parhztoms(pp->delay);
419 break;
421 case PARIOCSPARAM:
422 pp = &sc->sc_param;
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)
426 return(EINVAL);
427 pp->burst = upp->burst;
428 pp->timo = parmstohz(upp->timo);
429 pp->delay = parmstohz(upp->delay);
430 break;
432 default:
433 return(EINVAL);
435 return (error);
439 parhztoms(int h)
441 int m = h;
443 if (m > 0)
444 m = m * 1000 / hz;
445 return(m);
449 parmstohz(int m)
451 int h = m;
453 if (h > 0) {
454 h = h * hz / 1000;
455 if (h == 0)
456 h = 1000 / hz;
458 return(h);
461 /* stuff below here if for interrupt driven output of data thru
462 the parallel port. */
464 int partimeout_pending;
465 int parsend_pending;
467 void
468 parintr(void *arg)
470 int s, mask;
472 mask = (int)arg;
473 s = splclock();
475 intio_set_sicilian_intr(intio_get_sicilian_intr() &
476 ~SICILIAN_INTR_PAR);
478 #ifdef DEBUG
479 if (pardebug & PDB_INTERRUPT)
480 printf("parintr %d(%s)\n", mask, mask ? "FLG" : "tout");
481 #endif
482 /* if invoked from timeout handler, mask will be 0,
483 * if from interrupt, it will contain the cia-icr mask,
484 * which is != 0
486 if (mask) {
487 if (partimeout_pending)
488 callout_stop(&intr_callout);
489 if (parsend_pending)
490 parsend_pending = 0;
493 /* either way, there won't be a timeout pending any longer */
494 partimeout_pending = 0;
496 wakeup(parintr);
497 splx(s);
501 parsendch(struct par_softc *sc, u_char ch)
503 int error = 0;
504 int s;
506 /* if either offline, busy or out of paper, wait for that
507 condition to clear */
508 s = spl1();
509 while (!error
510 && (parsend_pending
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
518 the second, etc. */
519 parsend_pending = 0;
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))) {
524 #ifdef DEBUG
525 if (pardebug & PDB_INTERRUPT)
526 printf("parsendch interrupted, error = %d\n", error);
527 #endif
528 if (partimeout_pending)
529 callout_stop(&intr_callout);
531 partimeout_pending = 0;
535 if (!error) {
536 #ifdef DEBUG
537 if (pardebug & PDB_INTERRUPT)
538 printf("#%d", ch);
539 #endif
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() |
544 SICILIAN_INTR_PAR);
545 DELAY(1);
546 bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_STROBE, 1);
547 parsend_pending = 1;
550 splx(s);
552 return error;
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.. */
566 return orig_len;