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