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