Apply by doing: cd /usr/src patch -p0 < 005_audio.patch Then build and install a new kernel. Index: sys/dev/audio.c =================================================================== RCS file: /cvs/src/sys/dev/audio.c,v retrieving revision 1.101 diff -u -p sys/dev/audio.c --- sys/dev/audio.c 16 Jan 2009 23:07:33 -0000 1.101 +++ sys/dev/audio.c 24 Apr 2009 13:54:02 -0000 @@ -860,8 +860,6 @@ audio_init_ringbuffer(struct audio_ringbuffer *rp) rp->stamp_last = 0; rp->drops = 0; rp->pdrops = 0; - rp->copying = 0; - rp->needfill = 0; rp->mmapped = 0; } @@ -1138,12 +1136,6 @@ audio_drain(struct audio_softc *sc) * XXX This should be done some other way to avoid * playing silence. */ -#ifdef DIAGNOSTIC - if (cb->copying) { - printf("audio_drain: copying in progress!?!\n"); - cb->copying = 0; - } -#endif drops = cb->drops; error = 0; s = splaudio(); @@ -1233,7 +1225,7 @@ audio_read(dev_t dev, struct uio *uio, int ioflag) struct audio_softc *sc = audio_cd.cd_devs[unit]; struct audio_ringbuffer *cb = &sc->sc_rr; u_char *outp; - int error, s, used, cc, n; + int error, s, cc, n, resid; if (cb->mmapped) return EINVAL; @@ -1279,7 +1271,7 @@ audio_read(dev_t dev, struct uio *uio, int ioflag) } return (error); } - while (uio->uio_resid > 0 && !error) { + while (uio->uio_resid > 0) { s = splaudio(); while (cb->used <= 0) { if (!sc->sc_rbus && !sc->sc_rr.pause) { @@ -1302,34 +1294,28 @@ audio_read(dev_t dev, struct uio *uio, int ioflag) return error; } } - used = cb->used; + resid = uio->uio_resid * sc->sc_rparams.factor; outp = cb->outp; - cb->copying = 1; - splx(s); - cc = used - cb->usedlow; /* maximum to read */ + cc = cb->used - cb->usedlow; /* maximum to read */ n = cb->end - outp; - if (n < cc) - cc = n; /* don't read beyond end of buffer */ - - /* and no more than we want */ - if (uio->uio_resid < cc / sc->sc_rparams.factor) - cc = uio->uio_resid * sc->sc_rparams.factor; - + if (cc > n) + cc = n; /* don't read beyond end of buffer */ + + if (cc > resid) + cc = resid; /* and no more than we want */ + cb->used -= cc; + cb->outp += cc; + if (cb->outp >= cb->end) + cb->outp = cb->start; + splx(s); + DPRINTFN(1,("audio_read: outp=%p, cc=%d\n", outp, cc)); if (sc->sc_rparams.sw_code) sc->sc_rparams.sw_code(sc->hw_hdl, outp, cc); - DPRINTFN(1,("audio_read: outp=%p, cc=%d\n", outp, cc)); error = uiomove(outp, cc / sc->sc_rparams.factor, uio); - used -= cc; - outp += cc; - if (outp >= cb->end) - outp = cb->start; - s = splaudio(); - cb->outp = outp; - cb->used = used; - cb->copying = 0; - splx(s); + if (error) + return error; } - return (error); + return 0; } void @@ -1473,8 +1459,8 @@ audio_write(dev_t dev, struct uio *uio, int ioflag) int unit = AUDIOUNIT(dev); struct audio_softc *sc = audio_cd.cd_devs[unit]; struct audio_ringbuffer *cb = &sc->sc_pr; - u_char *inp, *einp; - int saveerror, error, s, n, cc, used; + u_char *inp; + int error, s, n, cc, resid, avail; DPRINTFN(2, ("audio_write: sc=%p(unit=%d) count=%d used=%d(hi=%d)\n", sc, unit, uio->uio_resid, sc->sc_pr.used, sc->sc_pr.usedhigh)); @@ -1513,12 +1499,18 @@ audio_write(dev_t dev, struct uio *uio, int ioflag) sc->sc_pparams.precision, sc->sc_pparams.channels, sc->sc_pparams.sw_code, sc->sc_pparams.factor)); - error = 0; - while (uio->uio_resid > 0 && !error) { + while (uio->uio_resid > 0) { s = splaudio(); while (cb->used >= cb->usedhigh) { DPRINTFN(2, ("audio_write: sleep used=%d lowat=%d hiwat=%d\n", cb->used, cb->usedlow, cb->usedhigh)); + if (!sc->sc_pbus && !cb->pause) { + error = audiostartp(sc); + if (error) { + splx(s); + return error; + } + } if (ioflag & IO_NDELAY) { splx(s); return (EWOULDBLOCK); @@ -1531,103 +1523,36 @@ audio_write(dev_t dev, struct uio *uio, int ioflag) return error; } } - used = cb->used; + resid = uio->uio_resid * sc->sc_pparams.factor; + avail = cb->end - cb->inp; inp = cb->inp; - cb->copying = 1; - splx(s); - cc = cb->usedhigh - used; /* maximum to write */ - n = cb->end - inp; - if (sc->sc_pparams.factor != 1) { - /* Compensate for software coding expansion factor. */ - n /= sc->sc_pparams.factor; - cc /= sc->sc_pparams.factor; - } - if (n < cc) - cc = n; /* don't write beyond end of buffer */ - if (uio->uio_resid < cc) - cc = uio->uio_resid; /* and no more than we have */ - -#ifdef DIAGNOSTIC + cc = cb->usedhigh - cb->used; + if (cc > resid) + cc = resid; + if (cc > avail) + cc = avail; + cb->inp += cc; + if (cb->inp >= cb->end) + cb->inp = cb->start; + cb->used += cc; /* - * This should never happen since the block size and and - * block pointers are always nicely aligned. + * This is a very suboptimal way of keeping track of + * silence in the buffer, but it is simple. */ - if (cc == 0) { - printf("audio_write: cc == 0, swcode=%p, factor=%d\n", - sc->sc_pparams.sw_code, sc->sc_pparams.factor); - cb->copying = 0; - return EINVAL; - } -#endif + sc->sc_sil_count = 0; + splx(s); + cc /= sc->sc_pparams.factor; DPRINTFN(1, ("audio_write: uiomove cc=%d inp=%p, left=%d\n", cc, inp, uio->uio_resid)); - n = uio->uio_resid; error = uiomove(inp, cc, uio); - cc = n - uio->uio_resid; /* number of bytes actually moved */ -#ifdef AUDIO_DEBUG if (error) - printf("audio_write:(1) uiomove failed %d; cc=%d inp=%p\n", - error, cc, inp); -#endif - /* - * Continue even if uiomove() failed because we may have - * gotten a partial block. - */ - + return 0; if (sc->sc_pparams.sw_code) { sc->sc_pparams.sw_code(sc->hw_hdl, inp, cc); - /* Adjust count after the expansion. */ - cc *= sc->sc_pparams.factor; DPRINTFN(1, ("audio_write: expanded cc=%d\n", cc)); } - - einp = cb->inp + cc; - if (einp >= cb->end) - einp = cb->start; - - s = splaudio(); - /* - * This is a very suboptimal way of keeping track of - * silence in the buffer, but it is simple. - */ - sc->sc_sil_count = 0; - - cb->inp = einp; - cb->used += cc; - /* If the interrupt routine wants the last block filled AND - * the copy did not fill the last block completely it needs to - * be padded. - */ - if (cb->needfill && - (inp - cb->start) / cb->blksize == - (einp - cb->start) / cb->blksize) { - /* Figure out how many bytes there is to a block boundary. */ - cc = cb->blksize - (einp - cb->start) % cb->blksize; - DPRINTF(("audio_write: partial fill %d\n", cc)); - } else - cc = 0; - cb->needfill = 0; - cb->copying = 0; - if (!sc->sc_pbus && !cb->pause) { - saveerror = error; - error = audiostartp(sc); - if (saveerror != 0) { - /* Report the first error that occurred. */ - error = saveerror; - } - } - splx(s); - if (cc) { - DPRINTFN(1, ("audio_write: fill %d\n", cc)); - if (sc->sc_pparams.sw_code) { - int ncc = cc / sc->sc_pparams.factor; - audio_fill_silence(&sc->sc_pparams, cb->start, einp, ncc); - sc->sc_pparams.sw_code(sc->hw_hdl, einp, ncc); - } else - audio_fill_silence(&sc->sc_pparams, cb->start, einp, cc); - } } - return (error); + return 0; } int @@ -2115,30 +2040,24 @@ audio_pint(void *v) cb->used -= blksize; if (cb->used < blksize) { /* we don't have a full block to use */ - if (cb->copying) { - /* writer is in progress, don't disturb */ - cb->needfill = 1; - DPRINTFN(1, ("audio_pint: copying in progress\n")); - } else { - inp = cb->inp; - cc = blksize - (inp - cb->start) % blksize; - if (cb->pause) - cb->pdrops += cc; - else { - cb->drops += cc; - sc->sc_playdrop += cc; - } - audio_pint_silence(sc, cb, inp, cc); - inp += cc; - if (inp >= cb->end) - inp = cb->start; - cb->inp = inp; - cb->used += cc; - - /* Clear next block so we keep ahead of the DMA. */ - if (cb->used + cc < cb->usedhigh) - audio_pint_silence(sc, cb, inp, blksize); + inp = cb->inp; + cc = blksize - (inp - cb->start) % blksize; + if (cb->pause) + cb->pdrops += cc; + else { + cb->drops += cc; + sc->sc_playdrop += cc; } + audio_pint_silence(sc, cb, inp, cc); + inp += cc; + if (inp >= cb->end) + inp = cb->start; + cb->inp = inp; + cb->used += cc; + + /* Clear next block so we keep ahead of the DMA. */ + if (cb->used + cc < cb->usedhigh) + audio_pint_silence(sc, cb, inp, blksize); } DPRINTFN(5, ("audio_pint: outp=%p cc=%d\n", cb->outp, blksize)); @@ -2232,7 +2151,7 @@ audio_rint(void *v) if (cb->outp >= cb->end) cb->outp = cb->start; cb->used -= blksize; - } else if (cb->used >= cb->usedhigh && !cb->copying) { + } else if (cb->used >= cb->usedhigh) { DPRINTFN(1, ("audio_rint: drops %lu\n", cb->drops)); cb->drops += blksize; cb->outp += blksize;