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