Index: /usr/src/sys/dev/sound/clone.h =================================================================== --- /usr/src/sys/dev/sound/clone.h +++ /usr/src/sys/dev/sound/clone.h @@ -116,6 +116,7 @@ uint32_t snd_clone_getdevflags(struct cdev *); uint32_t snd_clone_setdevflags(struct cdev *, uint32_t); int snd_clone_gc(struct snd_clone *); +void snd_clone_force_destroy_all(struct snd_clone *); void snd_clone_destroy(struct snd_clone *); int snd_clone_acquire(struct cdev *); int snd_clone_release(struct cdev *); Index: /usr/src/sys/dev/sound/clone.c =================================================================== --- /usr/src/sys/dev/sound/clone.c +++ /usr/src/sys/dev/sound/clone.c @@ -41,6 +41,7 @@ #include #endif +#include #include /* @@ -448,7 +449,27 @@ return (pruned); } +/* + * Requare: + * PCM_GIANT_ENTER(d); + * PCM_LOCK(d); + * PCM_WAIT(d); + * PCM_ACQUIRE(d); + */ void +snd_clone_force_destroy_all(struct snd_clone *c) +{ + struct snd_clone_entry *ce, *tce; + + SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); + + TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) { + dsp_close_locked(ce->devt, 0, 0, NULL); + ce->devt = NULL; + } +} + +void snd_clone_destroy(struct snd_clone *c) { struct snd_clone_entry *ce, *tmp; Index: /usr/src/sys/dev/sound/pcm/dsp.h =================================================================== --- /usr/src/sys/dev/sound/pcm/dsp.h +++ /usr/src/sys/dev/sound/pcm/dsp.h @@ -31,9 +31,12 @@ #ifndef _PCMDSP_H_ #define _PCMDSP_H_ +#include + extern struct cdevsw dsp_cdevsw; struct dsp_cdevinfo; +struct snddev_info; char *dsp_unit2name(char *, size_t, int); int dsp_oss_audioinfo(struct cdev *, oss_audioinfo *); @@ -41,4 +44,6 @@ void dsp_cdevinfo_init(struct snddev_info *); void dsp_cdevinfo_flush(struct snddev_info *); +int dsp_close_locked(struct cdev *, int, int, struct thread *); + #endif /* !_PCMDSP_H_ */ Index: /usr/src/sys/dev/sound/pcm/dsp.c =================================================================== --- /usr/src/sys/dev/sound/pcm/dsp.c +++ /usr/src/sys/dev/sound/pcm/dsp.c @@ -696,23 +696,14 @@ return (0); } -static int -dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td) +int +dsp_close_locked(struct cdev *i_dev, int flags, int mode, struct thread *td) { + int sg_ids, rdref, wdref; + struct snddev_info *d; struct pcm_channel *rdch, *wrch, *volch; - struct snddev_info *d; - int sg_ids, rdref, wdref; d = dsp_get_info(i_dev); - if (!DSP_REGISTERED(d, i_dev)) - return (EBADF); - - PCM_GIANT_ENTER(d); - - PCM_LOCK(d); - PCM_WAIT(d); - PCM_ACQUIRE(d); - rdch = PCM_RDCH(i_dev); wrch = PCM_WRCH(i_dev); volch = PCM_VOLCH(i_dev); @@ -806,12 +797,33 @@ (void)snd_clone_unref(i_dev); PCM_LOCK(d); + return (0); +} + +static int +dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td) +{ + int ret; + struct snddev_info *d; + + d = dsp_get_info(i_dev); + if (!DSP_REGISTERED(d, i_dev)) + return (EBADF); + + PCM_GIANT_ENTER(d); + + PCM_LOCK(d); + PCM_WAIT(d); + PCM_ACQUIRE(d); + + ret = dsp_close_locked(i_dev, flags, mode, td); + PCM_RELEASE(d); PCM_UNLOCK(d); PCM_GIANT_LEAVE(d); - return (0); + return (ret); } static __inline int Index: /usr/src/sys/dev/sound/pcm/mixer.c =================================================================== --- /usr/src/sys/dev/sound/pcm/mixer.c +++ /usr/src/sys/dev/sound/pcm/mixer.c @@ -771,25 +771,14 @@ d = device_get_softc(dev); pdev = mixer_get_devt(dev); - if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL) + if (d == NULL || pdev == NULL || (m = pdev->si_drv1) == NULL) return EBADF; - m = pdev->si_drv1; KASSERT(m != NULL, ("NULL snd_mixer")); KASSERT(m->type == MIXER_TYPE_PRIMARY, ("%s(): illegal mixer type=%d", __func__, m->type)); - snd_mtxlock(m->lock); - - if (m->busy) { - snd_mtxunlock(m->lock); - return EBUSY; - } - - /* destroy dev can sleep --hps */ - - snd_mtxunlock(m->lock); - + d->mixer_dev = NULL; pdev->si_drv1 = NULL; destroy_dev(pdev); @@ -809,7 +798,6 @@ snd_mtxfree(m->lock); kobj_delete((kobj_t)m, M_MIXER); - d->mixer_dev = NULL; --mixer_count; Index: /usr/src/sys/dev/sound/pcm/sound.c =================================================================== --- /usr/src/sys/dev/sound/pcm/sound.c +++ /usr/src/sys/dev/sound/pcm/sound.c @@ -1142,10 +1142,7 @@ pcm_unregister(device_t dev) { struct snddev_info *d; - struct pcm_channel *ch; - struct thread *td; - td = curthread; d = device_get_softc(dev); if (!PCM_ALIVE(d)) { @@ -1163,43 +1160,18 @@ } PCM_ACQUIRE(d); - PCM_UNLOCK(d); - CHN_FOREACH(ch, d, channels.pcm) { - CHN_LOCK(ch); - if (ch->refcount > 0) { - device_printf(dev, - "unregister: channel %s busy (pid %d)\n", - ch->name, ch->pid); - CHN_UNLOCK(ch); - PCM_RELEASE_QUICK(d); - return (EBUSY); - } - CHN_UNLOCK(ch); - } - if (d->clones != NULL) { - if (snd_clone_busy(d->clones) != 0) { - device_printf(dev, "unregister: clone busy\n"); - PCM_RELEASE_QUICK(d); - return (EBUSY); - } else { - PCM_LOCK(d); - (void)snd_clone_disable(d->clones); - PCM_UNLOCK(d); - } + (void)snd_clone_disable(d->clones); + PCM_GIANT_ENTER(d); + snd_clone_force_destroy_all(d->clones); + PCM_GIANT_LEAVE(d); } - if (mixer_uninit(dev) == EBUSY) { - device_printf(dev, "unregister: mixer busy\n"); - PCM_LOCK(d); - if (d->clones != NULL) - (void)snd_clone_enable(d->clones); - PCM_RELEASE(d); - PCM_UNLOCK(d); - return (EBUSY); - } + PCM_UNLOCK(d); + mixer_uninit(dev); + /* remove /dev/sndstat entry first */ sndstat_unregister(dev); Index: /usr/src/sys/dev/sound/usb/uaudio.c =================================================================== --- /usr/src/sys/dev/sound/usb/uaudio.c +++ /usr/src/sys/dev/sound/usb/uaudio.c @@ -1204,7 +1204,8 @@ error = pcm_unregister(dev); } else { if (sc->sc_mixer_init) { - error = mixer_uninit(dev); + error = 0; + mixer_uninit(dev); } }