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