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