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