par.c revision 1.19 1 /* $NetBSD: par.c,v 1.19 2000/03/16 16:37:20 kleink Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ppi.c 7.3 (Berkeley) 12/16/90
36 */
37
38 /*
39 * parallel port interface
40 */
41
42 #include "par.h"
43 #if NPAR > 0
44
45 #include <sys/param.h>
46 #include <sys/errno.h>
47 #include <sys/uio.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50 #include <sys/file.h>
51 #include <sys/systm.h>
52 #include <sys/proc.h>
53
54 #include <amiga/amiga/device.h>
55 #include <amiga/amiga/cia.h>
56 #include <amiga/dev/parioctl.h>
57
58 #include <sys/conf.h>
59 #include <machine/conf.h>
60
61 struct par_softc {
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
67 } *par_softcp;
68
69 #define getparsp(x) (x > 0 ? NULL : par_softcp)
70
71 /* sc_flags values */
72 #define PARF_ALIVE 0x01
73 #define PARF_OPEN 0x02
74 #define PARF_UIO 0x04
75 #define PARF_TIMO 0x08
76 #define PARF_DELAY 0x10
77 #define PARF_OREAD 0x40
78 #define PARF_OWRITE 0x80
79
80 #define UNIT(x) minor(x)
81
82 #ifdef DEBUG
83 int pardebug = 0;
84 #define PDB_FOLLOW 0x01
85 #define PDB_IO 0x02
86 #define PDB_INTERRUPT 0x04
87 #define PDB_NOCHECK 0x80
88 #endif
89
90 int parrw __P((dev_t, struct uio *));
91 int parhztoms __P((int));
92 int parmstohz __P((int));
93 int parsend __P((u_char *, int));
94 int parreceive __P((u_char *, int));
95 int parsendch __P((u_char));
96
97 void partimo __P((void *));
98 void parstart __P((void *));
99 void parintr __P((void *));
100
101 void parattach __P((struct device *, struct device *, void *));
102 int parmatch __P((struct device *, struct cfdata *, void *));
103
104 struct cfattach par_ca = {
105 sizeof(struct device), parmatch, parattach
106 };
107
108 /*ARGSUSED*/
109 int
110 parmatch(pdp, cfp, auxp)
111 struct device *pdp;
112 struct cfdata *cfp;
113 void *auxp;
114 {
115 static int par_found = 0;
116
117 if (!matchname((char *)auxp, "par") || par_found)
118 return(0);
119
120 par_found = 1;
121 return(1);
122 }
123
124 void
125 parattach(pdp, dp, auxp)
126 struct device *pdp, *dp;
127 void *auxp;
128 {
129 par_softcp = (struct par_softc *)dp;
130
131 #ifdef DEBUG
132 if ((pardebug & PDB_NOCHECK) == 0)
133 #endif
134 par_softcp->sc_flags = PARF_ALIVE;
135 printf("\n");
136 }
137
138 int
139 paropen(dev, flags, mode, p)
140 dev_t dev;
141 int flags;
142 int mode;
143 struct proc *p;
144 {
145 int unit = UNIT(dev);
146 struct par_softc *sc = getparsp(unit);
147
148 if (unit >= NPAR || (sc->sc_flags & PARF_ALIVE) == 0)
149 return(ENXIO);
150 #ifdef DEBUG
151 if (pardebug & PDB_FOLLOW) {
152 printf("paropen(%x, %x): flags %x, ",
153 dev, flags, sc->sc_flags);
154 printf ("port = $%x\n", ((ciab.pra ^ CIAB_PRA_SEL)
155 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
156 }
157 #endif
158 if (sc->sc_flags & PARF_OPEN)
159 return(EBUSY);
160 /* can either read or write, but not both */
161 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE))
162 return EINVAL;
163
164 sc->sc_flags |= PARF_OPEN;
165
166 if (flags & FREAD)
167 sc->sc_flags |= PARF_OREAD;
168 else
169 sc->sc_flags |= PARF_OWRITE;
170
171 sc->sc_burst = PAR_BURST;
172 sc->sc_timo = parmstohz(PAR_TIMO);
173 sc->sc_delay = parmstohz(PAR_DELAY);
174 /* enable interrupts for CIAA-FLG */
175 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
176 return(0);
177 }
178
179 int
180 parclose(dev, flags, mode, p)
181 dev_t dev;
182 int flags;
183 int mode;
184 struct proc *p;
185 {
186 int unit = UNIT(dev);
187 struct par_softc *sc = getparsp(unit);
188
189 #ifdef DEBUG
190 if (pardebug & PDB_FOLLOW)
191 printf("parclose(%x, %x): flags %x\n",
192 dev, flags, sc->sc_flags);
193 #endif
194 sc->sc_flags &= ~(PARF_OPEN|PARF_OREAD|PARF_OWRITE);
195 /* don't allow interrupts for CIAA-FLG any longer */
196 ciaa.icr = CIA_ICR_FLG;
197 return(0);
198 }
199
200 void
201 parstart(arg)
202 void *arg;
203 {
204 struct par_softc *sc;
205 int unit;
206
207 unit = (int)arg;
208 sc = getparsp(unit);
209 #ifdef DEBUG
210 if (pardebug & PDB_FOLLOW)
211 printf("parstart(%x)\n", unit);
212 #endif
213 sc->sc_flags &= ~PARF_DELAY;
214 wakeup(sc);
215 }
216
217 void
218 partimo(arg)
219 void *arg;
220 {
221 struct par_softc *sc;
222 int unit;
223
224 unit = (int) arg;
225 sc = getparsp(unit);
226 #ifdef DEBUG
227 if (pardebug & PDB_FOLLOW)
228 printf("partimo(%x)\n", unit);
229 #endif
230 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
231 wakeup(sc);
232 }
233
234 int
235 parread(dev, uio, flags)
236 dev_t dev;
237 struct uio *uio;
238 int flags;
239 {
240
241 #ifdef DEBUG
242 if (pardebug & PDB_FOLLOW)
243 printf("parread(%x, %p)\n", dev, uio);
244 #endif
245 return (parrw(dev, uio));
246 }
247
248
249 int
250 parwrite(dev, uio, flags)
251 dev_t dev;
252 struct uio *uio;
253 int flags;
254 {
255
256 #ifdef DEBUG
257 if (pardebug & PDB_FOLLOW)
258 printf("parwrite(%x, %p)\n", dev, uio);
259 #endif
260 return (parrw(dev, uio));
261 }
262
263
264 int
265 parrw(dev, uio)
266 dev_t dev;
267 register struct uio *uio;
268 {
269 int unit = UNIT(dev);
270 register struct par_softc *sc = getparsp(unit);
271 register int s, len, cnt;
272 register char *cp;
273 int error = 0, gotdata = 0;
274 int buflen;
275 char *buf;
276
277 len = 0;
278 cnt = 0;
279 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
280 return EINVAL;
281
282 if (uio->uio_resid == 0)
283 return(0);
284
285 #ifdef DEBUG
286 if (pardebug & (PDB_FOLLOW|PDB_IO))
287 printf("parrw(%x, %p, %c): burst %d, timo %d, resid %x\n",
288 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
289 sc->sc_burst, sc->sc_timo, uio->uio_resid);
290 #endif
291 buflen = min(sc->sc_burst, uio->uio_resid);
292 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
293 sc->sc_flags |= PARF_UIO;
294 if (sc->sc_timo > 0)
295 {
296 sc->sc_flags |= PARF_TIMO;
297 timeout(partimo, (void *)unit, sc->sc_timo);
298 }
299 while (uio->uio_resid > 0)
300 {
301 len = min(buflen, uio->uio_resid);
302 cp = buf;
303 if (uio->uio_rw == UIO_WRITE)
304 {
305 error = uiomove(cp, len, uio);
306 if (error)
307 break;
308 }
309 again:
310 s = splbio();
311 #if 0
312 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0)
313 sleep(sc, PRIBIO+1);
314 #endif
315 /*
316 * Check if we timed out during sleep or uiomove
317 */
318 (void) spllowersoftclock();
319 if ((sc->sc_flags & PARF_UIO) == 0)
320 {
321 #ifdef DEBUG
322 if (pardebug & PDB_IO)
323 printf("parrw: uiomove/sleep timo, flags %x\n",
324 sc->sc_flags);
325 #endif
326 if (sc->sc_flags & PARF_TIMO)
327 {
328 untimeout(partimo, (void *)unit);
329 sc->sc_flags &= ~PARF_TIMO;
330 }
331 splx(s);
332 break;
333 }
334 splx(s);
335 /*
336 * Perform the operation
337 */
338 if (uio->uio_rw == UIO_WRITE)
339 cnt = parsend (cp, len);
340 else
341 cnt = parreceive (cp, len);
342
343 if (cnt < 0)
344 {
345 error = -cnt;
346 break;
347 }
348
349 s = splbio();
350 #if 0
351 hpibfree(&sc->sc_dq);
352 #endif
353 #ifdef DEBUG
354 if (pardebug & PDB_IO)
355 printf("parrw: %s(%p, %d) -> %d\n",
356 uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt);
357 #endif
358 splx(s);
359 if (uio->uio_rw == UIO_READ)
360 {
361 if (cnt)
362 {
363 error = uiomove(cp, cnt, uio);
364 if (error)
365 break;
366 gotdata++;
367 }
368 /*
369 * Didn't get anything this time, but did in the past.
370 * Consider us done.
371 */
372 else if (gotdata)
373 break;
374 }
375 s = splsoftclock();
376 /*
377 * Operation timeout (or non-blocking), quit now.
378 */
379 if ((sc->sc_flags & PARF_UIO) == 0)
380 {
381 #ifdef DEBUG
382 if (pardebug & PDB_IO)
383 printf("parrw: timeout/done\n");
384 #endif
385 splx(s);
386 break;
387 }
388 /*
389 * Implement inter-read delay
390 */
391 if (sc->sc_delay > 0)
392 {
393 sc->sc_flags |= PARF_DELAY;
394 timeout(parstart, (void *)unit, sc->sc_delay);
395 error = tsleep(sc, PCATCH | (PZERO - 1), "par-cdelay", 0);
396 if (error)
397 {
398 splx(s);
399 break;
400 }
401 }
402 splx(s);
403 /*
404 * Must not call uiomove again til we've used all data
405 * that we already grabbed.
406 */
407 if (uio->uio_rw == UIO_WRITE && cnt != len)
408 {
409 cp += cnt;
410 len -= cnt;
411 cnt = 0;
412 goto again;
413 }
414 }
415 s = splsoftclock();
416 if (sc->sc_flags & PARF_TIMO)
417 {
418 untimeout(partimo, (void *)unit);
419 sc->sc_flags &= ~PARF_TIMO;
420 }
421 if (sc->sc_flags & PARF_DELAY)
422 {
423 untimeout(parstart, (void *)unit);
424 sc->sc_flags &= ~PARF_DELAY;
425 }
426 splx(s);
427 /*
428 * Adjust for those chars that we uiomove'ed but never wrote
429 */
430 if (uio->uio_rw == UIO_WRITE && cnt != len)
431 {
432 uio->uio_resid += (len - cnt);
433 #ifdef DEBUG
434 if (pardebug & PDB_IO)
435 printf("parrw: short write, adjust by %d\n",
436 len-cnt);
437 #endif
438 }
439 free(buf, M_DEVBUF);
440 #ifdef DEBUG
441 if (pardebug & (PDB_FOLLOW|PDB_IO))
442 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
443 #endif
444 return (error);
445 }
446
447 int
448 parioctl(dev, cmd, data, flag, p)
449 dev_t dev;
450 u_long cmd;
451 caddr_t data;
452 int flag;
453 struct proc *p;
454 {
455 struct par_softc *sc = getparsp(UNIT(dev));
456 struct parparam *pp, *upp;
457 int error = 0;
458
459 switch (cmd)
460 {
461 case PARIOCGPARAM:
462 pp = &sc->sc_param;
463 upp = (struct parparam *)data;
464 upp->burst = pp->burst;
465 upp->timo = parhztoms(pp->timo);
466 upp->delay = parhztoms(pp->delay);
467 break;
468
469 case PARIOCSPARAM:
470 pp = &sc->sc_param;
471 upp = (struct parparam *)data;
472 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
473 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
474 return(EINVAL);
475 pp->burst = upp->burst;
476 pp->timo = parmstohz(upp->timo);
477 pp->delay = parmstohz(upp->delay);
478 break;
479
480 default:
481 return(EINVAL);
482 }
483 return (error);
484 }
485
486 int
487 parhztoms(h)
488 int h;
489 {
490 extern int hz;
491 register int m = h;
492
493 if (m > 0)
494 m = m * 1000 / hz;
495 return(m);
496 }
497
498 int
499 parmstohz(m)
500 int m;
501 {
502 extern int hz;
503 register int h = m;
504
505 if (h > 0) {
506 h = h * hz / 1000;
507 if (h == 0)
508 h = 1000 / hz;
509 }
510 return(h);
511 }
512
513 /* stuff below here if for interrupt driven output of data thru
514 the parallel port. */
515
516 int partimeout_pending;
517 int parsend_pending;
518
519 void
520 parintr(arg)
521 void *arg;
522 {
523 int s, mask;
524
525 mask = (int)arg;
526 s = splclock();
527
528 #ifdef DEBUG
529 if (pardebug & PDB_INTERRUPT)
530 printf("parintr %s\n", mask ? "FLG" : "tout");
531 #endif
532 /*
533 * if invoked from timeout handler, mask will be 0,
534 * if from interrupt, it will contain the cia-icr mask,
535 * which is != 0
536 */
537 if (mask) {
538 if (partimeout_pending)
539 untimeout(parintr, 0);
540 if (parsend_pending)
541 parsend_pending = 0;
542 }
543
544 /* either way, there won't be a timeout pending any longer */
545 partimeout_pending = 0;
546
547 wakeup(parintr);
548 splx(s);
549 }
550
551 int
552 parsendch (ch)
553 u_char ch;
554 {
555 int error = 0;
556 int s;
557
558 /* if either offline, busy or out of paper, wait for that
559 condition to clear */
560 s = splclock();
561 while (!error
562 && (parsend_pending
563 || ((ciab.pra ^ CIAB_PRA_SEL)
564 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))))
565 {
566 extern int hz;
567
568 #ifdef DEBUG
569 if (pardebug & PDB_INTERRUPT)
570 printf ("parsendch, port = $%x\n",
571 ((ciab.pra ^ CIAB_PRA_SEL)
572 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
573 #endif
574 /* wait a second, and try again */
575 timeout(parintr, 0, hz);
576 partimeout_pending = 1;
577 /* this is essentially a flipflop to have us wait for the
578 first character being transmitted when trying to transmit
579 the second, etc. */
580 parsend_pending = 0;
581 /* it's quite important that a parallel putc can be
582 interrupted, given the possibility to lock a printer
583 in an offline condition.. */
584 if ((error = tsleep(parintr, PCATCH | (PZERO - 1), "parsendch", 0)) > 0)
585 {
586 #ifdef DEBUG
587 if (pardebug & PDB_INTERRUPT)
588 printf ("parsendch interrupted, error = %d\n", error);
589 #endif
590 if (partimeout_pending)
591 untimeout(parintr, 0);
592
593 partimeout_pending = 0;
594 }
595 }
596
597 if (! error)
598 {
599 #ifdef DEBUG
600 if (pardebug & PDB_INTERRUPT)
601 printf ("#%d", ch);
602 #endif
603 ciaa.prb = ch;
604 parsend_pending = 1;
605 }
606
607 splx (s);
608
609 return error;
610 }
611
612
613 int
614 parsend (buf, len)
615 u_char *buf;
616 int len;
617 {
618 int err, orig_len = len;
619
620 /* make sure I/O lines are setup right for output */
621
622 /* control lines set to input */
623 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY);
624 /* data lines to output */
625 ciaa.ddrb = 0xff;
626
627 for (; len; len--, buf++)
628 if ((err = parsendch (*buf)) != 0)
629 return err < 0 ? -EINTR : -err;
630
631 /* either all or nothing.. */
632 return orig_len;
633 }
634
635
636
637 int
638 parreceive (buf, len)
639 u_char *buf;
640 int len;
641 {
642 /* oh deary me, something's gotta be left to be implemented
643 later... */
644 return 0;
645 }
646
647
648 #endif
649