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