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