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