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