diff --git a/share/man/man4/snd_uaudio.4 b/share/man/man4/snd_uaudio.4 --- a/share/man/man4/snd_uaudio.4 +++ b/share/man/man4/snd_uaudio.4 @@ -86,16 +86,6 @@ by .An Hiten Pandya Aq Mt hmp@FreeBSD.org . .Sh BUGS -The -.Tn PCM -framework in -.Fx -only supports synchronous device detach. -That means all mixer and DSP character devices belonging to a given -USB audio device must be closed when receiving an error on a DSP read, -a DSP write or a DSP IOCTL request. -Else the USB audio driver will wait for this to happen, preventing -enumeration of new devices on the parenting USB controller. .Pp Some USB audio devices might refuse to work properly unless the sample rate is configured the same for both recording and playback, even if diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -1193,22 +1193,31 @@ 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); + if (ch->flags & CHN_F_SLEEPING) { + /* + * We are detaching, so do not wait for the timeout in + * chn_read()/chn_write(). Wake up the sleeping thread + * and kill the channel immediately. + */ + cv_broadcast(&ch->intr_cv); + ch->flags |= CHN_F_DEAD; } CHN_UNLOCK(ch); } if (d->clones != NULL) { +again: if (snd_clone_busy(d->clones) != 0) { - device_printf(dev, "unregister: clone busy\n"); PCM_RELEASE_QUICK(d); - return (EBUSY); + /* + * XXX Introduce a 1-second delay to make sure + * dsp_close() has finished, so that we can destroy any + * busy clones safely. Since chn_sleep() has been + * interrupted already, we don't need to worry about + * getting stuck waiting for the channel to timeout. + */ + pause("CLONEWAIT", 1 * hz + 1); + goto again; } else { PCM_LOCK(d); (void)snd_clone_disable(d->clones); @@ -1216,15 +1225,7 @@ } } - 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); - } + (void)mixer_uninit(dev); /* remove /dev/sndstat entry first */ sndstat_unregister(dev); diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -1250,20 +1250,12 @@ unsigned i = uaudio_get_child_index_by_dev(sc, dev); int error = 0; -repeat: - if (sc->sc_child[i].pcm_registered) { + if (sc->sc_child[i].pcm_registered) error = pcm_unregister(dev); - } else { - if (sc->sc_child[i].mixer_init) - error = mixer_uninit(dev); - } + else if (sc->sc_child[i].mixer_init) + error = mixer_uninit(dev); - if (error) { - device_printf(dev, "Waiting for sound application to exit!\n"); - usb_pause_mtx(NULL, 2 * hz); - goto repeat; /* try again */ - } - return (0); /* success */ + return (error); } static int