par.c revision 1.2 1 /*
2 * Copyright (c) 1982, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)ppi.c 7.3 (Berkeley) 12/16/90
34 * $Id: par.c,v 1.2 1993/10/30 23:41:28 mw Exp $
35 */
36
37 /*
38 * parallel port interface
39 */
40
41 #include "par.h"
42 #if NPAR > 0
43
44 #include "sys/param.h"
45 #include "sys/errno.h"
46 #include "sys/uio.h"
47 #include "sys/malloc.h"
48 #include "sys/file.h"
49 #include "sys/systm.h"
50
51 #include "device.h"
52 #include "parioctl.h"
53 #include "../amiga/cia.h"
54
55 int parattach(), parstart(), partimo();
56 void parintr();
57 struct driver pardriver = {
58 parattach, "par", parstart,
59 };
60
61 struct par_softc {
62 int sc_flags;
63 struct amiga_device *sc_ad;
64 struct parparam sc_param;
65 #define sc_burst sc_param.burst
66 #define sc_timo sc_param.timo
67 #define sc_delay sc_param.delay
68 } par_softc[NPAR];
69
70 /* sc_flags values */
71 #define PARF_ALIVE 0x01
72 #define PARF_OPEN 0x02
73 #define PARF_UIO 0x04
74 #define PARF_TIMO 0x08
75 #define PARF_DELAY 0x10
76 #define PARF_OREAD 0x40
77 #define PARF_OWRITE 0x80
78
79 #define UNIT(x) minor(x)
80
81 #ifdef DEBUG
82 int pardebug = 0;
83 #define PDB_FOLLOW 0x01
84 #define PDB_IO 0x02
85 #define PDB_INTERRUPT 0x04
86 #define PDB_NOCHECK 0x80
87 #endif
88
89 parattach(ad)
90 register struct amiga_device *ad;
91 {
92 register struct par_softc *sc = &par_softc[ad->amiga_unit];
93
94 #ifdef DEBUG
95 if ((pardebug & PDB_NOCHECK) == 0)
96 #endif
97 sc->sc_flags = PARF_ALIVE;
98 sc->sc_ad = ad;
99 return(1);
100 }
101
102 paropen(dev, flags)
103 dev_t dev;
104 {
105 register int unit = UNIT(dev);
106 register struct par_softc *sc = &par_softc[unit];
107
108 if (unit >= NPAR || (sc->sc_flags & PARF_ALIVE) == 0)
109 return(ENXIO);
110 #ifdef DEBUG
111 if (pardebug & PDB_FOLLOW)
112 {
113 printf("paropen(%x, %x): flags %x, ",
114 dev, flags, sc->sc_flags);
115 printf ("port = $%x\n",
116 ((ciab.pra ^ CIAB_PRA_SEL)
117 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
118 }
119 #endif
120 if (sc->sc_flags & PARF_OPEN)
121 return(EBUSY);
122 /* can either read or write, but not both */
123 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE))
124 return EINVAL;
125
126 sc->sc_flags |= PARF_OPEN;
127 if (flags & FREAD)
128 sc->sc_flags |= PARF_OREAD;
129 else
130 sc->sc_flags |= PARF_OWRITE;
131 sc->sc_burst = PAR_BURST;
132 sc->sc_timo = parmstohz(PAR_TIMO);
133 sc->sc_delay = parmstohz(PAR_DELAY);
134 /* enable interrupts for CIAA-FLG */
135 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
136 return(0);
137 }
138
139 parclose(dev, flags)
140 dev_t dev;
141 {
142 register int unit = UNIT(dev);
143 register struct par_softc *sc = &par_softc[unit];
144
145 #ifdef DEBUG
146 if (pardebug & PDB_FOLLOW)
147 printf("parclose(%x, %x): flags %x\n",
148 dev, flags, sc->sc_flags);
149 #endif
150 sc->sc_flags &= ~(PARF_OPEN|PARF_OREAD|PARF_OWRITE);
151 /* don't allow interrupts for CIAA-FLG any longer */
152 ciaa.icr = CIA_ICR_FLG;
153 return(0);
154 }
155
156 parstart(unit)
157 int unit;
158 {
159 #ifdef DEBUG
160 if (pardebug & PDB_FOLLOW)
161 printf("parstart(%x)\n", unit);
162 #endif
163 par_softc[unit].sc_flags &= ~PARF_DELAY;
164 wakeup(&par_softc[unit]);
165 }
166
167 partimo(unit)
168 int unit;
169 {
170 #ifdef DEBUG
171 if (pardebug & PDB_FOLLOW)
172 printf("partimo(%x)\n", unit);
173 #endif
174 par_softc[unit].sc_flags &= ~(PARF_UIO|PARF_TIMO);
175 wakeup(&par_softc[unit]);
176 }
177
178 parread(dev, uio)
179 dev_t dev;
180 struct uio *uio;
181 {
182
183 #ifdef DEBUG
184 if (pardebug & PDB_FOLLOW)
185 printf("parread(%x, %x)\n", dev, uio);
186 #endif
187 return (parrw(dev, uio));
188 }
189
190 parwrite(dev, uio)
191 dev_t dev;
192 struct uio *uio;
193 {
194
195 #ifdef DEBUG
196 if (pardebug & PDB_FOLLOW)
197 printf("parwrite(%x, %x)\n", dev, uio);
198 #endif
199 return (parrw(dev, uio));
200 }
201
202 parrw(dev, uio)
203 dev_t dev;
204 register struct uio *uio;
205 {
206 int unit = UNIT(dev);
207 register struct par_softc *sc = &par_softc[unit];
208 register int s, len, cnt;
209 register char *cp;
210 int error = 0, gotdata = 0;
211 int buflen;
212 char *buf;
213
214 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
215 return EINVAL;
216
217 if (uio->uio_resid == 0)
218 return(0);
219
220 #ifdef DEBUG
221 if (pardebug & (PDB_FOLLOW|PDB_IO))
222 printf("parrw(%x, %x, %c): burst %d, timo %d, resid %x\n",
223 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
224 sc->sc_burst, sc->sc_timo, uio->uio_resid);
225 #endif
226 buflen = MIN(sc->sc_burst, uio->uio_resid);
227 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
228 sc->sc_flags |= PARF_UIO;
229 if (sc->sc_timo > 0)
230 {
231 sc->sc_flags |= PARF_TIMO;
232 timeout(partimo, unit, sc->sc_timo);
233 }
234 while (uio->uio_resid > 0)
235 {
236 len = MIN(buflen, uio->uio_resid);
237 cp = buf;
238 if (uio->uio_rw == UIO_WRITE)
239 {
240 error = uiomove(cp, len, uio);
241 if (error)
242 break;
243 }
244 again:
245 s = splbio();
246 #if 0
247 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0)
248 sleep(sc, PRIBIO+1);
249 #endif
250 /*
251 * Check if we timed out during sleep or uiomove
252 */
253 (void) splsoftclock();
254 if ((sc->sc_flags & PARF_UIO) == 0)
255 {
256 #ifdef DEBUG
257 if (pardebug & PDB_IO)
258 printf("parrw: uiomove/sleep timo, flags %x\n",
259 sc->sc_flags);
260 #endif
261 if (sc->sc_flags & PARF_TIMO)
262 {
263 untimeout(partimo, unit);
264 sc->sc_flags &= ~PARF_TIMO;
265 }
266 splx(s);
267 break;
268 }
269 splx(s);
270 /*
271 * Perform the operation
272 */
273 if (uio->uio_rw == UIO_WRITE)
274 cnt = parsend (cp, len);
275 else
276 cnt = parreceive (cp, len);
277
278 if (cnt < 0)
279 {
280 error = -cnt;
281 break;
282 }
283
284 s = splbio();
285 #if 0
286 hpibfree(&sc->sc_dq);
287 #endif
288 #ifdef DEBUG
289 if (pardebug & PDB_IO)
290 printf("parrw: %s(%x, %d) -> %d\n",
291 uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt);
292 #endif
293 splx(s);
294 if (uio->uio_rw == UIO_READ)
295 {
296 if (cnt)
297 {
298 error = uiomove(cp, cnt, uio);
299 if (error)
300 break;
301 gotdata++;
302 }
303 /*
304 * Didn't get anything this time, but did in the past.
305 * Consider us done.
306 */
307 else if (gotdata)
308 break;
309 }
310 s = splsoftclock();
311 /*
312 * Operation timeout (or non-blocking), quit now.
313 */
314 if ((sc->sc_flags & PARF_UIO) == 0)
315 {
316 #ifdef DEBUG
317 if (pardebug & PDB_IO)
318 printf("parrw: timeout/done\n");
319 #endif
320 splx(s);
321 break;
322 }
323 /*
324 * Implement inter-read delay
325 */
326 if (sc->sc_delay > 0)
327 {
328 sc->sc_flags |= PARF_DELAY;
329 timeout(parstart, unit, sc->sc_delay);
330 error = tsleep(sc, PCATCH|PZERO-1, "par-cdelay", 0);
331 if (error)
332 {
333 splx(s);
334 break;
335 }
336 }
337 splx(s);
338 /*
339 * Must not call uiomove again til we've used all data
340 * that we already grabbed.
341 */
342 if (uio->uio_rw == UIO_WRITE && cnt != len)
343 {
344 cp += cnt;
345 len -= cnt;
346 cnt = 0;
347 goto again;
348 }
349 }
350 s = splsoftclock();
351 if (sc->sc_flags & PARF_TIMO)
352 {
353 untimeout(partimo, unit);
354 sc->sc_flags &= ~PARF_TIMO;
355 }
356 if (sc->sc_flags & PARF_DELAY)
357 {
358 untimeout(parstart, unit);
359 sc->sc_flags &= ~PARF_DELAY;
360 }
361 splx(s);
362 /*
363 * Adjust for those chars that we uiomove'ed but never wrote
364 */
365 if (uio->uio_rw == UIO_WRITE && cnt != len)
366 {
367 uio->uio_resid += (len - cnt);
368 #ifdef DEBUG
369 if (pardebug & PDB_IO)
370 printf("parrw: short write, adjust by %d\n",
371 len-cnt);
372 #endif
373 }
374 free(buf, M_DEVBUF);
375 #ifdef DEBUG
376 if (pardebug & (PDB_FOLLOW|PDB_IO))
377 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
378 #endif
379 return (error);
380 }
381
382 int
383 parioctl(dev, cmd, data, flag)
384 dev_t dev;
385 int cmd;
386 caddr_t data;
387 int flag;
388 {
389 struct par_softc *sc = &par_softc[UNIT(dev)];
390 struct parparam *pp, *upp;
391 int error = 0;
392
393 switch (cmd)
394 {
395 case PARIOCGPARAM:
396 pp = &sc->sc_param;
397 upp = (struct parparam *)data;
398 upp->burst = pp->burst;
399 upp->timo = parhztoms(pp->timo);
400 upp->delay = parhztoms(pp->delay);
401 break;
402
403 case PARIOCSPARAM:
404 pp = &sc->sc_param;
405 upp = (struct parparam *)data;
406 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
407 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
408 return(EINVAL);
409 pp->burst = upp->burst;
410 pp->timo = parmstohz(upp->timo);
411 pp->delay = parmstohz(upp->delay);
412 break;
413
414 default:
415 return(EINVAL);
416 }
417 return (error);
418 }
419
420 int
421 parhztoms(h)
422 int h;
423 {
424 extern int hz;
425 register int m = h;
426
427 if (m > 0)
428 m = m * 1000 / hz;
429 return(m);
430 }
431
432 int
433 parmstohz(m)
434 int m;
435 {
436 extern int hz;
437 register int h = m;
438
439 if (h > 0) {
440 h = h * hz / 1000;
441 if (h == 0)
442 h = 1000 / hz;
443 }
444 return(h);
445 }
446
447 /* stuff below here if for interrupt driven output of data thru
448 the parallel port. */
449
450 int partimeout_pending;
451 int parsend_pending;
452
453 void
454 parintr (mask)
455 int mask;
456 {
457 int s = splclock();
458 #ifdef DEBUG
459 if (pardebug & PDB_INTERRUPT)
460 printf ("parintr %s\n", mask ? "FLG" : "tout");
461 #endif
462 /* if invoked from timeout handler, mask will be 0, if from
463 interrupt, it will contain the cia-icr mask, which is != 0 */
464 if (mask)
465 {
466 if (partimeout_pending)
467 untimeout ((timeout_t) parintr, 0);
468 if (parsend_pending)
469 parsend_pending = 0;
470 }
471
472 /* either way, there won't be a timeout pending any longer */
473 partimeout_pending = 0;
474
475 wakeup (parintr);
476 splx (s);
477 }
478
479 int
480 parsendch (ch)
481 u_char ch;
482 {
483 int error = 0;
484 int s;
485
486 /* if either offline, busy or out of paper, wait for that
487 condition to clear */
488 s = splclock();
489 while (!error
490 && (parsend_pending
491 || ((ciab.pra ^ CIAB_PRA_SEL)
492 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))))
493 {
494 extern int hz;
495
496 #ifdef DEBUG
497 if (pardebug & PDB_INTERRUPT)
498 printf ("parsendch, port = $%x\n",
499 ((ciab.pra ^ CIAB_PRA_SEL)
500 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
501 #endif
502 /* wait a second, and try again */
503 timeout ((timeout_t) parintr, 0, hz);
504 partimeout_pending = 1;
505 /* this is essentially a flipflop to have us wait for the
506 first character being transmitted when trying to transmit
507 the second, etc. */
508 parsend_pending = 0;
509 /* it's quite important that a parallel putc can be
510 interrupted, given the possibility to lock a printer
511 in an offline condition.. */
512 if (error = tsleep (parintr, PCATCH|PZERO-1, "parsendch", 0))
513 {
514 #ifdef DEBUG
515 if (pardebug & PDB_INTERRUPT)
516 printf ("parsendch interrupted, error = %d\n", error);
517 #endif
518 if (partimeout_pending)
519 untimeout ((timeout_t) parintr, 0);
520
521 partimeout_pending = 0;
522 }
523 }
524
525 if (! error)
526 {
527 #ifdef DEBUG
528 if (pardebug & PDB_INTERRUPT)
529 printf ("#%d", ch);
530 #endif
531 ciaa.prb = ch;
532 parsend_pending = 1;
533 }
534
535 splx (s);
536
537 return error;
538 }
539
540
541 int
542 parsend (buf, len)
543 u_char *buf;
544 int len;
545 {
546 int err, orig_len = len;
547
548 /* make sure I/O lines are setup right for output */
549
550 /* control lines set to input */
551 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY);
552 /* data lines to output */
553 ciaa.ddrb = 0xff;
554
555 for (; len; len--, buf++)
556 if (err = parsendch (*buf))
557 return err < 0 ? -EINTR : -err;
558
559 /* either all or nothing.. */
560 return orig_len;
561 }
562
563
564
565 int
566 parreceive (buf, len)
567 u_char *buf;
568 int len;
569 {
570 /* oh deary me, something's gotta be left to be implemented
571 later... */
572 return 0;
573 }
574
575
576 #endif
577