summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm/sound.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pcm/sound.c')
-rw-r--r--sys/dev/sound/pcm/sound.c76
1 files changed, 57 insertions, 19 deletions
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 3ba4636..edb765e 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -75,7 +75,23 @@ snd_mtxcreate(const char *desc, const char *type)
m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
if (m == NULL)
return NULL;
- mtx_init(m, desc, type, MTX_DEF | MTX_RECURSE);
+ mtx_init(m, desc, type, MTX_DEF);
+ return m;
+#else
+ return (void *)0xcafebabe;
+#endif
+}
+
+void *
+snd_chnmtxcreate(const char *desc, const char *type)
+{
+#ifdef USING_MUTEX
+ struct mtx *m;
+
+ m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (m == NULL)
+ return NULL;
+ mtx_init(m, desc, type, MTX_DEF | MTX_DUPOK);
return m;
#else
return (void *)0xcafebabe;
@@ -188,13 +204,16 @@ pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid, int chnum)
/* try to create a vchan */
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
+ CHN_LOCK(c);
if (!SLIST_EMPTY(&c->children)) {
err = vchan_create(c);
+ CHN_UNLOCK(c);
if (!err)
return pcm_chnalloc(d, direction, pid, -1);
else
device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err);
- }
+ } else
+ CHN_UNLOCK(c);
}
}
}
@@ -250,15 +269,19 @@ pcm_setmaxautovchans(struct snddev_info *d, int num)
if (num > 0 && d->vchancount == 0) {
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
+ CHN_LOCK(c);
if ((c->direction == PCMDIR_PLAY) && !(c->flags & CHN_F_BUSY)) {
c->flags |= CHN_F_BUSY;
err = vchan_create(c);
if (err) {
- device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err);
c->flags &= ~CHN_F_BUSY;
- }
+ CHN_UNLOCK(c);
+ device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err);
+ } else
+ CHN_UNLOCK(c);
return;
}
+ CHN_UNLOCK(c);
}
}
if (num == 0 && d->vchancount > 0) {
@@ -313,7 +336,7 @@ sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
v = snd_maxautovchans;
error = sysctl_handle_int(oidp, &v, sizeof(v), req);
if (error == 0 && req->newptr != NULL) {
- if (v < 0 || v >= SND_MAXVCHANS)
+ if (v < 0 || v >= SND_MAXVCHANS || pcm_devclass == NULL)
return EINVAL;
if (v != snd_maxautovchans) {
for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) {
@@ -529,20 +552,23 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
err = pcm_chn_add(d, ch);
if (err) {
device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err);
- snd_mtxunlock(d->lock);
pcm_chn_destroy(ch);
return err;
}
+ CHN_LOCK(ch);
if (snd_maxautovchans > 0 && (d->flags & SD_F_AUTOVCHAN) &&
ch->direction == PCMDIR_PLAY && d->vchancount == 0) {
ch->flags |= CHN_F_BUSY;
err = vchan_create(ch);
if (err) {
- device_printf(d->dev, "vchan_create(%s) == %d\n", ch->name, err);
ch->flags &= ~CHN_F_BUSY;
+ CHN_UNLOCK(ch);
+ device_printf(d->dev, "vchan_create(%s) == %d\n", ch->name, err);
+ return err;
}
}
+ CHN_UNLOCK(ch);
return err;
}
@@ -866,11 +892,13 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
cnt = 0;
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
+ CHN_LOCK(c);
if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) {
cnt++;
if (c->flags & CHN_F_BUSY)
busy++;
}
+ CHN_UNLOCK(c);
}
newcnt = cnt;
@@ -888,23 +916,28 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
/* add new vchans - find a parent channel first */
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
+ CHN_LOCK(c);
/* not a candidate if not a play channel */
if (c->direction != PCMDIR_PLAY)
- continue;
+ goto next;
/* not a candidate if a virtual channel */
if (c->flags & CHN_F_VIRTUAL)
- continue;
+ goto next;
/* not a candidate if it's in use */
- if ((c->flags & CHN_F_BUSY) && (SLIST_EMPTY(&c->children)))
- continue;
- /*
- * if we get here we're a nonvirtual play channel, and either
- * 1) not busy
- * 2) busy with children, not directly open
- *
- * thus we can add children
- */
- goto addok;
+ if (!(c->flags & CHN_F_BUSY) ||
+ !(SLIST_EMPTY(&c->children)))
+ /*
+ * if we get here we're a nonvirtual
+ * play channel, and either
+ * 1) not busy
+ * 2) busy with children, not directly
+ * open
+ *
+ * thus we can add children
+ */
+ goto addok;
+next:
+ CHN_UNLOCK(c);
}
pcm_inprog(d, -1);
return EBUSY;
@@ -917,6 +950,7 @@ addok:
}
if (SLIST_EMPTY(&c->children))
c->flags &= ~CHN_F_BUSY;
+ CHN_UNLOCK(c);
} else if (newcnt < cnt) {
if (busy > newcnt) {
printf("cnt %d, newcnt %d, busy %d\n", cnt, newcnt, busy);
@@ -928,13 +962,17 @@ addok:
while (err == 0 && newcnt < cnt) {
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
+ CHN_LOCK(c);
if ((c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL)
goto remok;
+
+ CHN_UNLOCK(c);
}
snd_mtxunlock(d->lock);
pcm_inprog(d, -1);
return EINVAL;
remok:
+ CHN_UNLOCK(c);
err = vchan_destroy(c);
if (err == 0)
cnt--;
OpenPOWER on IntegriCloud