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