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