Page MenuHomeFreeBSD

D43545.id133277.diff
No OneTemporary

D43545.id133277.diff

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/clone.h b/sys/dev/sound/clone.h
--- a/sys/dev/sound/clone.h
+++ b/sys/dev/sound/clone.h
@@ -102,6 +102,7 @@
int snd_clone_enable(struct snd_clone *);
int snd_clone_disable(struct snd_clone *);
int snd_clone_getsize(struct snd_clone *);
+int snd_clone_getrefcount(struct snd_clone *);
int snd_clone_getmaxunit(struct snd_clone *);
int snd_clone_setmaxunit(struct snd_clone *, int);
int snd_clone_getdeadline(struct snd_clone *);
@@ -112,6 +113,8 @@
uint32_t snd_clone_setdevflags(struct cdev *, uint32_t);
int snd_clone_gc(struct snd_clone *);
void snd_clone_destroy(struct snd_clone *);
+void snd_clone_sleep(struct snd_clone *);
+void snd_clone_wakeup(struct snd_clone *);
int snd_clone_acquire(struct cdev *);
int snd_clone_release(struct cdev *);
int snd_clone_ref(struct cdev *);
diff --git a/sys/dev/sound/clone.c b/sys/dev/sound/clone.c
--- a/sys/dev/sound/clone.c
+++ b/sys/dev/sound/clone.c
@@ -37,10 +37,7 @@
#include "opt_snd.h"
#endif
-#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
#include <dev/sound/pcm/sound.h>
-#endif
-
#include <dev/sound/clone.h>
/*
@@ -80,6 +77,8 @@
struct snd_clone {
TAILQ_HEAD(link_head, snd_clone_entry) head;
struct timespec tsp;
+ struct cv cv;
+ struct mtx *lock;
int refcount;
int size;
int typemask;
@@ -115,6 +114,8 @@
("invalid clone flags=0x%08x", flags));
c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
+ c->lock = snd_mtxcreate("clone lock", "clone manager");
+ cv_init(&c->cv, "clone");
c->refcount = 0;
c->size = 0;
c->typemask = typemask;
@@ -188,6 +189,14 @@
return (c->size);
}
+int
+snd_clone_getrefcount(struct snd_clone *c)
+{
+ SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+ return (c->refcount);
+}
+
int
snd_clone_getmaxunit(struct snd_clone *c)
{
@@ -370,9 +379,31 @@
ce = tmp;
}
+ cv_destroy(&c->cv);
+ snd_mtxfree(c->lock);
free(c, M_DEVBUF);
}
+void
+snd_clone_sleep(struct snd_clone *c)
+{
+ SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+ /* Lock here since it's the only place where we need it. */
+ mtx_lock(c->lock);
+ cv_wait(&c->cv, c->lock);
+ mtx_unlock(c->lock);
+}
+
+void
+snd_clone_wakeup(struct snd_clone *c)
+{
+ SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+ mtx_assert(c->lock, MA_OWNED);
+ cv_broadcastpri(&c->cv, PRIBIO);
+}
+
/*
* snd_clone_acquire() : The vital part of concurrency management. Must be
* called somewhere at the beginning of open() handler. ENODEV is not really
@@ -489,6 +520,9 @@
(c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
(void)snd_clone_gc(c);
+ if (c->refcount == 0)
+ snd_clone_wakeup(ce->parent);
+
return (c->refcount);
}
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -320,7 +320,6 @@
pid_t pid, char *comm, int devunit);
int pcm_chnrelease(struct pcm_channel *c);
int pcm_chnref(struct pcm_channel *c, int ref);
-int pcm_inprog(struct snddev_info *d, int delta);
struct pcm_channel *pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo);
int pcm_chn_destroy(struct pcm_channel *ch);
@@ -379,7 +378,6 @@
struct snd_clone *clones;
unsigned devcount, playcount, reccount, pvchancount, rvchancount ;
unsigned flags;
- int inprog;
unsigned int bufsz;
void *devinfo;
device_t dev;
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
@@ -392,16 +392,6 @@
return (c->refcount);
}
-int
-pcm_inprog(struct snddev_info *d, int delta)
-{
- PCM_LOCKASSERT(d);
-
- d->inprog += delta;
-
- return (d->inprog);
-}
-
static void
pcm_setmaxautovchans(struct snddev_info *d, int num)
{
@@ -1127,7 +1117,6 @@
d->pvchanformat = 0;
d->rvchanrate = 0;
d->rvchanformat = 0;
- d->inprog = 0;
/*
* Create clone manager, disabled by default. Cloning will be
@@ -1182,50 +1171,43 @@
d->flags |= SD_F_DETACHING;
- if (d->inprog != 0) {
- device_printf(dev, "unregister: operation in progress\n");
- PCM_UNLOCK(d);
- return (EBUSY);
- }
-
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);
+ 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.
+ */
+ CHN_BROADCAST(&ch->intr_cv);
+ ch->flags |= CHN_F_DEAD;
}
CHN_UNLOCK(ch);
}
if (d->clones != NULL) {
- if (snd_clone_busy(d->clones) != 0) {
- device_printf(dev, "unregister: clone busy\n");
+ while (snd_clone_getrefcount(d->clones) > 0) {
PCM_RELEASE_QUICK(d);
- return (EBUSY);
- } else {
- PCM_LOCK(d);
- (void)snd_clone_disable(d->clones);
- PCM_UNLOCK(d);
+ /*
+ * Wait for all sleeping threads to exit so that we can
+ * destroy the clones safely. Since chn_sleep() has
+ * been interrupted already, we don't need to worry
+ * about getting stuck waiting for the channel to
+ * timeout.
+ */
+ snd_clone_sleep(d->clones);
+ PCM_ACQUIRE_QUICK(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);
+ (void)snd_clone_disable(d->clones);
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

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 8, 5:58 AM (16 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14529138
Default Alt Text
D43545.id133277.diff (7 KB)

Event Timeline