diff options
author | cg <cg@FreeBSD.org> | 2000-06-20 23:27:12 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 2000-06-20 23:27:12 +0000 |
commit | cc71ce279b47c761c710b6ca373564677dc63303 (patch) | |
tree | bf3ab11f1fea9b018349732564de44a049d8d6ef /sys | |
parent | 0790e5cf47ed3741eb769f7ab9ef76fdf5a55e02 (diff) | |
download | FreeBSD-src-cc71ce279b47c761c710b6ca373564677dc63303.zip FreeBSD-src-cc71ce279b47c761c710b6ca373564677dc63303.tar.gz |
fix a bug where opening for write would not fail if channel allocation failed
when playing, if we stall for 1s with no data advancing, abort and mark the
channel dead - fail all future operations
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/sound/pcm/channel.c | 17 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel.h | 3 | ||||
-rw-r--r-- | sys/dev/sound/pcm/datatypes.h | 2 | ||||
-rw-r--r-- | sys/dev/sound/pcm/dsp.c | 17 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.c | 2 |
5 files changed, 30 insertions, 11 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 45568be..9f81751 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -428,7 +428,7 @@ chn_wrintr(pcm_channel *c) int chn_write(pcm_channel *c, struct uio *buf) { - int ret = 0, timeout, res, newsize; + int ret = 0, timeout, res, newsize, count; long s; snd_dbuf *b = &c->buffer; snd_dbuf *bs = &c->buffer2nd; @@ -460,9 +460,6 @@ chn_write(pcm_channel *c, struct uio *buf) DEB(printf("pcm warning: frags reset to %d x %d\n", bs->blkcnt, bs->blksz)); } - /* Store the initial size in the uio. */ - res = buf->uio_resid; - /* * Fill up the secondary and DMA buffer. * chn_wrfeed*() takes care of the alignment. @@ -479,12 +476,18 @@ chn_write(pcm_channel *c, struct uio *buf) chn_start(c); if (ret == 0) { + count = hz; /* Wait until all samples are played in blocking mode. */ - while (buf->uio_resid > 0) { + while ((buf->uio_resid > 0) && (count > 0)) { /* Check for underflow before writing into the buffers. */ chn_checkunderflow(c); /* Fill up the buffers with new pcm data. */ + res = buf->uio_resid; while (chn_wrfeed2nd(c, buf) > 0); + if (buf->uio_resid < res) + count = hz; + else + count--; /* Have we finished to feed the secondary buffer? */ if (buf->uio_resid == 0) @@ -499,6 +502,10 @@ chn_write(pcm_channel *c, struct uio *buf) if (ret == EINTR || ret == ERESTART) break; } + if (count == 0) { + c->flags |= CHN_F_DEAD; + device_printf(c->parent->dev, "play interrupt timeout, channel dead\n"); + } } else ret = 0; c->flags &= ~CHN_F_WRITING; diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h index 0c13b65..23e31df 100644 --- a/sys/dev/sound/pcm/channel.h +++ b/sys/dev/sound/pcm/channel.h @@ -81,9 +81,10 @@ extern pcm_feeder feeder_root; #define CHN_F_NBIO 0x00004000 /* do non-blocking i/o */ #define CHN_F_INIT 0x00008000 /* changed parameters. need init */ #define CHN_F_MAPPED 0x00010000 /* has been mmap()ed */ +#define CHN_F_DEAD 0x00020000 -#define CHN_F_RESET (CHN_F_BUSY) +#define CHN_F_RESET (CHN_F_BUSY | CHN_F_DEAD) /* * This should be large enough to hold all pcm data between diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h index 67e1923..31df62b 100644 --- a/sys/dev/sound/pcm/datatypes.h +++ b/sys/dev/sound/pcm/datatypes.h @@ -121,6 +121,7 @@ struct _pcm_channel { int direction; snd_dbuf buffer, buffer2nd; + snddev_info *parent; void *devinfo; }; @@ -136,6 +137,7 @@ struct _snddev_info { unsigned flags; void *devinfo; pcm_swap_t *swap; + device_t dev; char status[SND_STATUSLEN]; }; diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index 6dfae6a..903de31 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -41,7 +41,7 @@ allocchn(snddev_info *d, int direction) pcm_channel *chns = (direction == PCMDIR_PLAY)? d->play : d->rec; int i, cnt = (direction == PCMDIR_PLAY)? d->playcount : d->reccount; for (i = 0; i < cnt; i++) { - if (!(chns[i].flags & CHN_F_BUSY)) { + if (!(chns[i].flags & (CHN_F_BUSY | CHN_F_DEAD))) { chns[i].flags |= CHN_F_BUSY; return &chns[i]; } @@ -94,8 +94,9 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype) if (oflags & FWRITE) { if (wrch == NULL) { wrch = allocchn(d, PCMDIR_PLAY); - if (!wrch && (oflags & FREAD)) { - rdch->flags &= ~CHN_F_BUSY; + if (!wrch) { + if (rdch && (oflags & FREAD)) + rdch->flags &= ~CHN_F_BUSY; return EBUSY; } } else return EBUSY; @@ -171,7 +172,7 @@ dsp_read(snddev_info *d, int chan, struct uio *buf, int flag) getchns(d, chan, &rdch, &wrch); KASSERT(rdch, ("dsp_read: nonexistant channel")); KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel")); - if (rdch->flags & CHN_F_MAPPED) return EINVAL; + if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) return EINVAL; if (!(rdch->flags & CHN_F_RUNNING)) rdch->flags |= CHN_F_RUNNING; return chn_read(rdch, buf); @@ -187,7 +188,7 @@ dsp_write(snddev_info *d, int chan, struct uio *buf, int flag) getchns(d, chan, &rdch, &wrch); KASSERT(wrch, ("dsp_write: nonexistant channel")); KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel")); - if (wrch->flags & CHN_F_MAPPED) return EINVAL; + if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) return EINVAL; if (!(wrch->flags & CHN_F_RUNNING)) wrch->flags |= CHN_F_RUNNING; return chn_write(wrch, buf); @@ -203,6 +204,12 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) rdch = d->arec[chan]; wrch = d->aplay[chan]; + if (rdch && (rdch->flags & CHN_F_DEAD)) + rdch = NULL; + if (wrch && (wrch->flags & CHN_F_DEAD)) + wrch = NULL; + if (!(rdch || wrch)) + return EINVAL; /* * all routines are called with int. blocked. Make sure that * ints are re-enabled when calling slow or blocking functions! diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 0d3a84c..c5c0b6d 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -106,6 +106,7 @@ pcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo) } ch = (dir == PCMDIR_PLAY)? &d->play[d->playcount] : &d->rec[d->reccount]; *ch = *templ; + ch->parent = d; if (chn_init(ch, devinfo, dir)) { device_printf(dev, "chn_init() for %s:%d failed\n", (dir == PCMDIR_PLAY)? "play" : "record", @@ -174,6 +175,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0), UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit); + d->dev = dev; d->devinfo = devinfo; d->chancount = d->playcount = d->reccount = 0; sz = (numplay + numrec) * sizeof(pcm_channel *); |