Index: src/sys/dev/sound/pcm/vchan.c =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pcm/vchan.c,v retrieving revision 1.17.2.3 diff -u -r1.17.2.3 vchan.c --- src/sys/dev/sound/pcm/vchan.c 20 Jan 2006 03:55:58 -0000 1.17.2.3 +++ src/sys/dev/sound/pcm/vchan.c 4 Apr 2006 14:59:50 -0000 @@ -290,36 +290,50 @@ d = oidp->oid_arg1; if (!(d->flags & SD_F_AUTOVCHAN) || d->vchancount < 1) return EINVAL; + if (pcm_inprog(d, 1) != 1 && req->newptr != NULL) { + pcm_inprog(d, -1); + return EINPROGRESS; + } SLIST_FOREACH(sce, &d->channels, link) { c = sce->channel; CHN_LOCK(c); if (c->direction == PCMDIR_PLAY) { if (c->flags & CHN_F_VIRTUAL) { + /* Sanity check */ + if (ch != NULL && ch != c->parentchannel) { + CHN_UNLOCK(c); + pcm_inprog(d, -1); + return EINVAL; + } if (req->newptr != NULL && (c->flags & CHN_F_BUSY)) { CHN_UNLOCK(c); + pcm_inprog(d, -1); return EBUSY; } - if (ch == NULL) - ch = c->parentchannel; + } else if (c->flags & CHN_F_HAS_VCHAN) { + /* No way!! */ + if (ch != NULL) { + CHN_UNLOCK(c); + pcm_inprog(d, -1); + return EINVAL; + } + ch = c; + newspd = ch->speed; } } CHN_UNLOCK(c); } - if (ch != NULL) { - CHN_LOCK(ch); - newspd = ch->speed; - CHN_UNLOCK(ch); + if (ch == NULL) { + pcm_inprog(d, -1); + return EINVAL; } err = sysctl_handle_int(oidp, &newspd, sizeof(newspd), req); if (err == 0 && req->newptr != NULL) { - if (ch == NULL || newspd < 1 || - newspd < feeder_rate_ratemin || - newspd > feeder_rate_ratemax) - return EINVAL; - if (pcm_inprog(d, 1) != 1) { + if (newspd < 1 || newspd < feeder_rate_ratemin || + newspd > feeder_rate_ratemax) { pcm_inprog(d, -1); - return EINPROGRESS; + return EINVAL; } CHN_LOCK(ch); caps = chn_getcaps(ch); @@ -350,8 +364,8 @@ } } else CHN_UNLOCK(ch); - pcm_inprog(d, -1); } + pcm_inprog(d, -1); return err; } #endif @@ -507,8 +521,8 @@ parent->flags &= ~CHN_F_HAS_VCHAN; CHN_UNLOCK(parent); free(pce, M_DEVBUF); - pcm_chn_remove(d, child); - pcm_chn_destroy(child); + if (pcm_chn_remove(d, child) == 0) + pcm_chn_destroy(child); CHN_LOCK(parent); return err; } @@ -524,7 +538,8 @@ struct snddev_info *d = parent->parentsnddev; struct pcmchan_children *pce; struct snddev_channel *sce; - int err, last; + uint32_t spd; + int err; CHN_LOCK(parent); if (!(parent->flags & CHN_F_BUSY)) { @@ -546,24 +561,34 @@ gotch: SLIST_FOREACH(sce, &d->channels, link) { if (sce->channel == c) { - if (sce->dsp_devt) + if (sce->dsp_devt) { destroy_dev(sce->dsp_devt); - if (sce->dspW_devt) + sce->dsp_devt = NULL; + } + if (sce->dspW_devt) { destroy_dev(sce->dspW_devt); - if (sce->audio_devt) + sce->dspW_devt = NULL; + } + if (sce->audio_devt) { destroy_dev(sce->audio_devt); - if (sce->dspr_devt) + sce->audio_devt = NULL; + } + if (sce->dspr_devt) { destroy_dev(sce->dspr_devt); + sce->dspr_devt = NULL; + } + d->devcount--; break; } } SLIST_REMOVE(&parent->children, pce, pcmchan_children, link); free(pce, M_DEVBUF); - last = SLIST_EMPTY(&parent->children); - if (last) { - parent->flags &= ~CHN_F_BUSY; - parent->flags &= ~CHN_F_HAS_VCHAN; + if (SLIST_EMPTY(&parent->children)) { + parent->flags &= ~(CHN_F_BUSY | CHN_F_HAS_VCHAN); + spd = parent->speed; + if (chn_reset(parent, parent->format) == 0) + chn_setspeed(parent, spd); } /* remove us from our grandparent's channel list */ @@ -574,15 +599,6 @@ if (!err) err = pcm_chn_destroy(c); -#if 0 - if (!err && last) { - CHN_LOCK(parent); - chn_reset(parent, chn_getcaps(parent)->fmtlist[0]); - chn_setspeed(parent, chn_getcaps(parent)->minspeed); - CHN_UNLOCK(parent); - } -#endif - return err; }