par.c revision 1.5 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.5 1994/02/11 05:02:43 chopps 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((caddr_t) &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((caddr_t) &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((timeout_t) partimo, (caddr_t) 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((timeout_t) partimo, (caddr_t) 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((timeout_t) parstart, (caddr_t) unit, sc->sc_delay);
330 error = tsleep((caddr_t) 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((timeout_t) partimo, (caddr_t) unit);
354 sc->sc_flags &= ~PARF_TIMO;
355 }
356 if (sc->sc_flags & PARF_DELAY)
357 {
358 untimeout((timeout_t) parstart, (caddr_t) 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, p)
384 dev_t dev;
385 int cmd;
386 caddr_t data;
387 int flag;
388 struct proc *p;
389 {
390 struct par_softc *sc = &par_softc[UNIT(dev)];
391 struct parparam *pp, *upp;
392 int error = 0;
393
394 switch (cmd)
395 {
396 case PARIOCGPARAM:
397 pp = &sc->sc_param;
398 upp = (struct parparam *)data;
399 upp->burst = pp->burst;
400 upp->timo = parhztoms(pp->timo);
401 upp->delay = parhztoms(pp->delay);
402 break;
403
404 case PARIOCSPARAM:
405 pp = &sc->sc_param;
406 upp = (struct parparam *)data;
407 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
408 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
409 return(EINVAL);
410 pp->burst = upp->burst;
411 pp->timo = parmstohz(upp->timo);
412 pp->delay = parmstohz(upp->delay);
413 break;
414
415 default:
416 return(EINVAL);
417 }
418 return (error);
419 }
420
421 int
422 parhztoms(h)
423 int h;
424 {
425 extern int hz;
426 register int m = h;
427
428 if (m > 0)
429 m = m * 1000 / hz;
430 return(m);
431 }
432
433 int
434 parmstohz(m)
435 int m;
436 {
437 extern int hz;
438 register int h = m;
439
440 if (h > 0) {
441 h = h * hz / 1000;
442 if (h == 0)
443 h = 1000 / hz;
444 }
445 return(h);
446 }
447
448 /* stuff below here if for interrupt driven output of data thru
449 the parallel port. */
450
451 int partimeout_pending;
452 int parsend_pending;
453
454 void
455 parintr (mask)
456 int mask;
457 {
458 int s = splclock();
459 #ifdef DEBUG
460 if (pardebug & PDB_INTERRUPT)
461 printf ("parintr %s\n", mask ? "FLG" : "tout");
462 #endif
463 /* if invoked from timeout handler, mask will be 0, if from
464 interrupt, it will contain the cia-icr mask, which is != 0 */
465 if (mask)
466 {
467 if (partimeout_pending)
468 untimeout ((timeout_t) parintr, 0);
469 if (parsend_pending)
470 parsend_pending = 0;
471 }
472
473 /* either way, there won't be a timeout pending any longer */
474 partimeout_pending = 0;
475
476 wakeup ((caddr_t) parintr);
477 splx (s);
478 }
479
480 int
481 parsendch (ch)
482 u_char ch;
483 {
484 int error = 0;
485 int s;
486
487 /* if either offline, busy or out of paper, wait for that
488 condition to clear */
489 s = splclock();
490 while (!error
491 && (parsend_pending
492 || ((ciab.pra ^ CIAB_PRA_SEL)
493 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))))
494 {
495 extern int hz;
496
497 #ifdef DEBUG
498 if (pardebug & PDB_INTERRUPT)
499 printf ("parsendch, port = $%x\n",
500 ((ciab.pra ^ CIAB_PRA_SEL)
501 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
502 #endif
503 /* wait a second, and try again */
504 timeout ((timeout_t) parintr, 0, hz);
505 partimeout_pending = 1;
506 /* this is essentially a flipflop to have us wait for the
507 first character being transmitted when trying to transmit
508 the second, etc. */
509 parsend_pending = 0;
510 /* it's quite important that a parallel putc can be
511 interrupted, given the possibility to lock a printer
512 in an offline condition.. */
513 if (error = tsleep ((caddr_t) parintr, PCATCH|PZERO-1, "parsendch", 0))
514 {
515 #ifdef DEBUG
516 if (pardebug & PDB_INTERRUPT)
517 printf ("parsendch interrupted, error = %d\n", error);
518 #endif
519 if (partimeout_pending)
520 untimeout ((timeout_t) parintr, 0);
521
522 partimeout_pending = 0;
523 }
524 }
525
526 if (! error)
527 {
528 #ifdef DEBUG
529 if (pardebug & PDB_INTERRUPT)
530 printf ("#%d", ch);
531 #endif
532 ciaa.prb = ch;
533 parsend_pending = 1;
534 }
535
536 splx (s);
537
538 return error;
539 }
540
541
542 int
543 parsend (buf, len)
544 u_char *buf;
545 int len;
546 {
547 int err, orig_len = len;
548
549 /* make sure I/O lines are setup right for output */
550
551 /* control lines set to input */
552 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY);
553 /* data lines to output */
554 ciaa.ddrb = 0xff;
555
556 for (; len; len--, buf++)
557 if (err = parsendch (*buf))
558 return err < 0 ? -EINTR : -err;
559
560 /* either all or nothing.. */
561 return orig_len;
562 }
563
564
565
566 int
567 parreceive (buf, len)
568 u_char *buf;
569 int len;
570 {
571 /* oh deary me, something's gotta be left to be implemented
572 later... */
573 return 0;
574 }
575
576
577 #endif
578