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