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