xref: /netbsd-src/sys/arch/amiga/dev/par.c (revision 38023541164cff097d5fadec63134189b1453b8c)
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