summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm/sound.c
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2001-06-07 20:06:22 +0000
committercg <cg@FreeBSD.org>2001-06-07 20:06:22 +0000
commit88b6f276b2af09b2d63d82cd4e0535912a9141db (patch)
treeb656cff6fee0e17ae9ae6dba0d20452357cf9e8e /sys/dev/sound/pcm/sound.c
parentd6ce76b54bfd8517c26a090adf004c0728713bda (diff)
downloadFreeBSD-src-88b6f276b2af09b2d63d82cd4e0535912a9141db.zip
FreeBSD-src-88b6f276b2af09b2d63d82cd4e0535912a9141db.tar.gz
lock sound device when adding/removing channels
implement setblocksize for vchans don't panic when doing certain ioctls or aborting on a vchan xmms now works with vchans
Diffstat (limited to 'sys/dev/sound/pcm/sound.c')
-rw-r--r--sys/dev/sound/pcm/sound.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index a8b3910..7db70f9 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -174,28 +174,41 @@ pcm_chnalloc(struct snddev_info *d, int direction)
struct pcm_channel *c;
struct snddev_channel *sce;
+ snd_mtxlock(d->lock);
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
+ CHN_LOCK(c);
if ((c->direction == direction) && !(c->flags & CHN_F_BUSY)) {
c->flags |= CHN_F_BUSY;
+ CHN_UNLOCK(c);
+ snd_mtxunlock(d->lock);
return c;
}
+ CHN_UNLOCK(c);
}
+ snd_mtxunlock(d->lock);
return NULL;
}
int
pcm_chnfree(struct pcm_channel *c)
{
+ CHN_LOCK(c);
c->flags &= ~CHN_F_BUSY;
+ CHN_UNLOCK(c);
return 0;
}
int
pcm_chnref(struct pcm_channel *c, int ref)
{
+ int r;
+
+ CHN_LOCK(c);
c->refcount += ref;
- return c->refcount;
+ r = c->refcount;
+ CHN_UNLOCK(c);
+ return r;
}
#ifdef USING_DEVFS
@@ -337,6 +350,7 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
return ENOMEM;
}
+ snd_mtxlock(d->lock);
sce->channel = ch;
SLIST_INSERT_HEAD(&d->channels, sce, link);
@@ -352,6 +366,7 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
if (d->chancount++ == 0)
pcm_makelinks(NULL);
#endif
+ snd_mtxunlock(d->lock);
return 0;
}
@@ -363,10 +378,12 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
int unit = device_get_unit(d->dev);
dev_t pdev;
+ snd_mtxlock(d->lock);
SLIST_FOREACH(sce, &d->channels, link) {
if (sce->channel == ch)
goto gotit;
}
+ snd_mtxunlock(d->lock);
return EINVAL;
gotit:
d->chancount--;
@@ -383,6 +400,7 @@ gotit:
destroy_dev(pdev);
pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount));
destroy_dev(pdev);
+ snd_mtxunlock(d->lock);
return 0;
}
@@ -414,7 +432,9 @@ pcm_killchan(device_t dev)
struct snddev_info *d = device_get_softc(dev);
struct snddev_channel *sce;
+ snd_mtxlock(d->lock);
sce = SLIST_FIRST(&d->channels);
+ snd_mtxunlock(d->lock);
return pcm_chn_remove(d, sce->channel);
}
@@ -423,7 +443,10 @@ int
pcm_setstatus(device_t dev, char *str)
{
struct snddev_info *d = device_get_softc(dev);
+
+ snd_mtxlock(d->lock);
strncpy(d->status, str, SND_STATUSLEN);
+ snd_mtxunlock(d->lock);
return 0;
}
@@ -431,6 +454,7 @@ u_int32_t
pcm_getflags(device_t dev)
{
struct snddev_info *d = device_get_softc(dev);
+
return d->flags;
}
@@ -438,6 +462,7 @@ void
pcm_setflags(device_t dev, u_int32_t val)
{
struct snddev_info *d = device_get_softc(dev);
+
d->flags = val;
}
@@ -445,6 +470,7 @@ void *
pcm_getdevinfo(device_t dev)
{
struct snddev_info *d = device_get_softc(dev);
+
return d->devinfo;
}
@@ -455,6 +481,8 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
int sz, unit = device_get_unit(dev);
struct snddev_info *d = device_get_softc(dev);
+ d->lock = snd_mtxcreate(device_get_nameunit(dev));
+ snd_mtxlock(d->lock);
if (!pcm_devclass) {
pcm_devclass = device_get_devclass(dev);
status_dev = make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0),
@@ -492,13 +520,16 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
goto no;
}
#endif
-#if 0
+#if 1
vchan_initsys(d);
#endif
+ snd_mtxunlock(d->lock);
return 0;
no:
if (d->aplay) free(d->aplay, M_DEVBUF);
if (d->arec) free(d->arec, M_DEVBUF);
+ /* snd_mtxunlock(d->lock); */
+ snd_mtxfree(d->lock);
return ENXIO;
}
@@ -510,14 +541,17 @@ pcm_unregister(device_t dev)
struct snddev_channel *sce;
dev_t pdev;
+ snd_mtxlock(d->lock);
SLIST_FOREACH(sce, &d->channels, link) {
if (sce->channel->refcount > 0) {
device_printf(dev, "unregister: channel busy");
+ snd_mtxunlock(d->lock);
return EBUSY;
}
}
if (mixer_isbusy(d->mixer)) {
device_printf(dev, "unregister: mixer busy");
+ snd_mtxunlock(d->lock);
return EBUSY;
}
@@ -539,6 +573,8 @@ pcm_unregister(device_t dev)
chn_kill(d->fakechan);
fkchan_kill(d->fakechan);
+ /* snd_mtxunlock(d->lock); */
+ snd_mtxfree(d->lock);
return 0;
}
@@ -766,7 +802,9 @@ status_init(struct sbuf *s)
struct snddev_info *d;
struct snddev_channel *sce;
struct pcm_channel *c;
+#ifdef SNDSTAT_VERBOSE
struct pcm_feeder *f;
+#endif
sbuf_printf(s, "FreeBSD Audio Driver (newpcm) %s %s\nInstalled devices:\n",
__DATE__, __TIME__);
@@ -775,6 +813,7 @@ status_init(struct sbuf *s)
d = devclass_get_softc(pcm_devclass, i);
if (!d)
continue;
+ snd_mtxlock(d->lock);
dev = devclass_get_device(pcm_devclass, i);
sbuf_printf(s, "pcm%d: <%s> %s", i, device_get_desc(dev), d->status);
if (d->chancount > 0) {
@@ -824,6 +863,7 @@ status_init(struct sbuf *s)
#endif
} else
sbuf_printf(s, " (mixer only)\n");
+ snd_mtxunlock(d->lock);
}
sbuf_finish(s);
return sbuf_len(s);
OpenPOWER on IntegriCloud