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