コード例 #1
0
int
parrw(dev_t dev, register struct uio *uio)
{
  int unit = UNIT(dev);
  register struct par_softc *sc = getparsp(unit);
  register int s, len, cnt;
  register char *cp;
  int error = 0, gotdata = 0;
  int buflen;
  char *buf;

  len = 0;
  cnt = 0;
  if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
    return EINVAL;

  if (uio->uio_resid == 0)
    return(0);

#ifdef DEBUG
  if (pardebug & (PDB_FOLLOW|PDB_IO))
    printf("parrw(%llx, %p, %c): burst %d, timo %d, resid %x\n",
	   dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
	   sc->sc_burst, sc->sc_timo, uio->uio_resid);
#endif
  buflen = min(sc->sc_burst, uio->uio_resid);
  buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
  sc->sc_flags |= PARF_UIO;
  if (sc->sc_timo > 0)
    {
      sc->sc_flags |= PARF_TIMO;
      callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc);
    }
  while (uio->uio_resid > 0)
    {
      len = min(buflen, uio->uio_resid);
      cp = buf;
      if (uio->uio_rw == UIO_WRITE)
	{
	  error = uiomove(cp, len, uio);
	  if (error)
	    break;
	}
again:
#if 0
      if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0)
	sleep(sc, PRIBIO+1);
#endif
      /*
       * Check if we timed out during sleep or uiomove
       */
      s = splsoftclock();
      if ((sc->sc_flags & PARF_UIO) == 0)
	{
#ifdef DEBUG
	  if (pardebug & PDB_IO)
	    printf("parrw: uiomove/sleep timo, flags %x\n",
		   sc->sc_flags);
#endif
	  if (sc->sc_flags & PARF_TIMO)
	    {
	      callout_stop(&sc->sc_timo_ch);
	      sc->sc_flags &= ~PARF_TIMO;
	    }
	  splx(s);
	  break;
	}
      splx(s);
      /*
       * Perform the operation
       */
      if (uio->uio_rw == UIO_WRITE)
	cnt = parsend (cp, len);
      else
	cnt = parreceive (cp, len);

      if (cnt < 0)
	{
	  error = -cnt;
	  break;
	}

      s = splbio();
#if 0
      hpibfree(&sc->sc_dq);
#endif
#ifdef DEBUG
      if (pardebug & PDB_IO)
	printf("parrw: %s(%p, %d) -> %d\n",
	       uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt);
#endif
      splx(s);
      if (uio->uio_rw == UIO_READ)
	{
	  if (cnt)
	    {
	      error = uiomove(cp, cnt, uio);
	      if (error)
		break;
	      gotdata++;
	    }
	  /*
	   * Didn't get anything this time, but did in the past.
	   * Consider us done.
	   */
	  else if (gotdata)
	    break;
	}
      s = splsoftclock();
      /*
       * Operation timeout (or non-blocking), quit now.
       */
      if ((sc->sc_flags & PARF_UIO) == 0)
	{
#ifdef DEBUG
	  if (pardebug & PDB_IO)
	    printf("parrw: timeout/done\n");
#endif
	  splx(s);
	  break;
	}
      /*
       * Implement inter-read delay
       */
      if (sc->sc_delay > 0)
	{
	  sc->sc_flags |= PARF_DELAY;
	  callout_reset(&sc->sc_start_ch, sc->sc_delay, parstart, sc);
	  error = tsleep(sc, PCATCH | (PZERO - 1), "par-cdelay", 0);
	  if (error)
	    {
	      splx(s);
	      break;
	    }
	}
      splx(s);
      /*
       * Must not call uiomove again til we've used all data
       * that we already grabbed.
       */
      if (uio->uio_rw == UIO_WRITE && cnt != len)
	{
	  cp += cnt;
	  len -= cnt;
	  cnt = 0;
	  goto again;
	}
    }
  s = splsoftclock();
  if (sc->sc_flags & PARF_TIMO)
    {
      callout_stop(&sc->sc_timo_ch);
      sc->sc_flags &= ~PARF_TIMO;
    }
  if (sc->sc_flags & PARF_DELAY)
    {
      callout_stop(&sc->sc_start_ch);
      sc->sc_flags &= ~PARF_DELAY;
    }
  splx(s);
  /*
   * Adjust for those chars that we uiomove'ed but never wrote
   */
  if (uio->uio_rw == UIO_WRITE && cnt != len)
    {
      uio->uio_resid += (len - cnt);
#ifdef DEBUG
      if (pardebug & PDB_IO)
	printf("parrw: short write, adjust by %d\n",
	       len-cnt);
#endif
    }
  free(buf, M_DEVBUF);
#ifdef DEBUG
  if (pardebug & (PDB_FOLLOW|PDB_IO))
    printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
#endif
  return (error);
}
コード例 #2
0
ファイル: par.c プロジェクト: lacombar/netbsd-alc
int
parrw(dev_t dev, struct uio *uio)
{
	int unit = UNIT(dev);
	struct par_softc *sc = device_lookup_private(&par_cd, unit);
	int len=0xdeadbeef;	/* XXX: shutup gcc */
	int s, cnt=0;
	char *cp;
	int error = 0;
	int buflen;
	char *buf;
	
	if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
		return EINVAL;
	
	if (uio->uio_resid == 0)
		return(0);
	
	buflen = min(sc->sc_burst, uio->uio_resid);
	buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
	sc->sc_flags |= PARF_UIO;
	if (sc->sc_timo > 0) {
		sc->sc_flags |= PARF_TIMO;
		callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc);
	}
	while (uio->uio_resid > 0) {
		len = min(buflen, uio->uio_resid);
		cp = buf;
		if (uio->uio_rw == UIO_WRITE) {
			error = uiomove(cp, len, uio);
			if (error)
				break;
		}
	      again:
		s = splsoftclock();
		/*
		 * Check if we timed out during sleep or uiomove
		 */
		if ((sc->sc_flags & PARF_UIO) == 0) {
#ifdef DEBUG
			if (pardebug & PDB_IO)
				printf("parrw: uiomove/sleep timo, flags %x\n",
				       sc->sc_flags);
#endif
			if (sc->sc_flags & PARF_TIMO) {
				callout_stop(&sc->sc_timo_ch);
				sc->sc_flags &= ~PARF_TIMO;
			}
			splx(s);
			break;
		}
		splx(s);
		/*
		 * Perform the operation
		 */
		cnt = parsend(sc, cp, len);
		if (cnt < 0) {
			error = -cnt;
			break;
		}
		
		s = splsoftclock();
		/*
		 * Operation timeout (or non-blocking), quit now.
		 */
		if ((sc->sc_flags & PARF_UIO) == 0) {
#ifdef DEBUG
			if (pardebug & PDB_IO)
				printf("parrw: timeout/done\n");
#endif
			splx(s);
			break;
		}
		/*
		 * Implement inter-read delay
		 */
		if (sc->sc_delay > 0) {
			sc->sc_flags |= PARF_DELAY;
			callout_reset(&sc->sc_start_ch, sc->sc_delay,
			    parstart, sc);
			error = tsleep(sc, PCATCH|(PZERO-1), "par-cdelay", 0);
			if (error) {
				splx(s);
				break;
			}
		}
		splx(s);
		/*
		 * Must not call uiomove again til we've used all data
		 * that we already grabbed.
		 */
		if (uio->uio_rw == UIO_WRITE && cnt != len) {
			cp += cnt;
			len -= cnt;
			cnt = 0;
			goto again;
		}
	}
	s = splsoftclock();
	if (sc->sc_flags & PARF_TIMO) {
		callout_stop(&sc->sc_timo_ch);
		sc->sc_flags &= ~PARF_TIMO;
	}
	if (sc->sc_flags & PARF_DELAY)	{
		callout_stop(&sc->sc_start_ch);
		sc->sc_flags &= ~PARF_DELAY;
	}
	splx(s);
	/*
	 * Adjust for those chars that we uiomove'ed but never wrote
	 */
	/*
	 * XXXjdolecek: this len usage is wrong, this will be incorrect
	 * if the transfer size is longer than sc_burst
	 */
	if (uio->uio_rw == UIO_WRITE && cnt != len) {
		uio->uio_resid += (len - cnt);
#ifdef DEBUG
			if (pardebug & PDB_IO)
				printf("parrw: short write, adjust by %d\n",
				       len-cnt);
#endif
	}
	free(buf, M_DEVBUF);
#ifdef DEBUG
	if (pardebug & (PDB_FOLLOW|PDB_IO))
		printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
#endif
	return (error);
}