sys/dev/sound/pcm/sndstat.c:
* General spl* cleanup. It doesn't serve any purpose anymore. * Nuke sndstat_busy(). Addition of sndstat_acquire() / sndstat_release() for sndstat exclusive access. [1] sys/dev/sound/pcm/sound.c: * Remove duplicate SLIST_INIT() * Use sndstat_acquire() / release() to lock / release the entire sndstat during pcm_unregister(). This should fix LOR #159 [1] sys/dev/sound/pcm/sound.h: * Definition of SD_F_SOFTVOL (part of feeder volume) * Nuke sndstat_busy(). Addition of sndstat_acquire() / sndstat_release() for exclusive sndstat access. [1] Submitted by: Ariff Abdullah <skywizard@MyBSD.org.my> LOR: 159 [1] Discussed with: yongari [1]
This commit is contained in:
parent
62340837c3
commit
28ef3fb011
@ -84,20 +84,17 @@ static int sndstat_prepare(struct sbuf *s);
|
|||||||
static int
|
static int
|
||||||
sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
|
sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
int error, verbose;
|
int error, verbose;
|
||||||
|
|
||||||
verbose = sndstat_verbose;
|
verbose = sndstat_verbose;
|
||||||
error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
|
error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
|
||||||
if (error == 0 && req->newptr != NULL) {
|
if (error == 0 && req->newptr != NULL) {
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (verbose < 0 || verbose > 3)
|
if (verbose < 0 || verbose > 3)
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
else
|
else
|
||||||
sndstat_verbose = verbose;
|
sndstat_verbose = verbose;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -107,19 +104,15 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
|
|||||||
static int
|
static int
|
||||||
sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (sndstat_isopen) {
|
if (sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
sndstat_isopen = 1;
|
sndstat_isopen = 1;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
|
if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
|
||||||
error = ENXIO;
|
error = ENXIO;
|
||||||
goto out;
|
goto out;
|
||||||
@ -128,11 +121,9 @@ sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
error = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
|
error = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
|
||||||
out:
|
out:
|
||||||
if (error) {
|
if (error) {
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
sndstat_isopen = 0;
|
sndstat_isopen = 0;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
}
|
}
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -140,34 +131,26 @@ sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
static int
|
static int
|
||||||
sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (!sndstat_isopen) {
|
if (!sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBADF;
|
return EBADF;
|
||||||
}
|
}
|
||||||
sbuf_delete(&sndstat_sbuf);
|
sbuf_delete(&sndstat_sbuf);
|
||||||
sndstat_isopen = 0;
|
sndstat_isopen = 0;
|
||||||
|
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
|
sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
int l, err;
|
int l, err;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (!sndstat_isopen) {
|
if (!sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBADF;
|
return EBADF;
|
||||||
}
|
}
|
||||||
l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
|
l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
|
||||||
@ -175,7 +158,6 @@ sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
|
|||||||
sndstat_bufptr += l;
|
sndstat_bufptr += l;
|
||||||
|
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,10 +176,35 @@ sndstat_find(int type, int unit)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sndstat_acquire(void)
|
||||||
|
{
|
||||||
|
sx_xlock(&sndstat_lock);
|
||||||
|
if (sndstat_isopen) {
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
sndstat_isopen = 1;
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sndstat_release(void)
|
||||||
|
{
|
||||||
|
sx_xlock(&sndstat_lock);
|
||||||
|
if (!sndstat_isopen) {
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
sndstat_isopen = 0;
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sndstat_register(device_t dev, char *str, sndstat_handler handler)
|
sndstat_register(device_t dev, char *str, sndstat_handler handler)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
struct sndstat_entry *ent;
|
struct sndstat_entry *ent;
|
||||||
const char *devtype;
|
const char *devtype;
|
||||||
int type, unit;
|
int type, unit;
|
||||||
@ -228,14 +235,12 @@ sndstat_register(device_t dev, char *str, sndstat_handler handler)
|
|||||||
ent->unit = unit;
|
ent->unit = unit;
|
||||||
ent->handler = handler;
|
ent->handler = handler;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
|
SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
|
||||||
if (type == SS_TYPE_MODULE)
|
if (type == SS_TYPE_MODULE)
|
||||||
sndstat_files++;
|
sndstat_files++;
|
||||||
sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
|
sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -249,23 +254,19 @@ sndstat_registerfile(char *str)
|
|||||||
int
|
int
|
||||||
sndstat_unregister(device_t dev)
|
sndstat_unregister(device_t dev)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
struct sndstat_entry *ent;
|
struct sndstat_entry *ent;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
||||||
if (ent->dev == dev) {
|
if (ent->dev == dev) {
|
||||||
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
free(ent, M_DEVBUF);
|
free(ent, M_DEVBUF);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -273,24 +274,20 @@ sndstat_unregister(device_t dev)
|
|||||||
int
|
int
|
||||||
sndstat_unregisterfile(char *str)
|
sndstat_unregisterfile(char *str)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
struct sndstat_entry *ent;
|
struct sndstat_entry *ent;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
||||||
if (ent->dev == NULL && ent->str == str) {
|
if (ent->dev == NULL && ent->str == str) {
|
||||||
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
||||||
sndstat_files--;
|
sndstat_files--;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
free(ent, M_DEVBUF);
|
free(ent, M_DEVBUF);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -353,13 +350,9 @@ sndstat_init(void)
|
|||||||
static int
|
static int
|
||||||
sndstat_uninit(void)
|
sndstat_uninit(void)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (sndstat_isopen) {
|
if (sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,18 +360,11 @@ sndstat_uninit(void)
|
|||||||
destroy_dev(sndstat_dev);
|
destroy_dev(sndstat_dev);
|
||||||
sndstat_dev = 0;
|
sndstat_dev = 0;
|
||||||
|
|
||||||
splx(s);
|
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
sx_destroy(&sndstat_lock);
|
sx_destroy(&sndstat_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
sndstat_busy(void)
|
|
||||||
{
|
|
||||||
return (sndstat_isopen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sndstat_sysinit(void *p)
|
sndstat_sysinit(void *p)
|
||||||
{
|
{
|
||||||
|
@ -718,7 +718,6 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
|
|||||||
d->vchancount = 0;
|
d->vchancount = 0;
|
||||||
d->inprog = 0;
|
d->inprog = 0;
|
||||||
|
|
||||||
SLIST_INIT(&d->channels);
|
|
||||||
SLIST_INIT(&d->channels);
|
SLIST_INIT(&d->channels);
|
||||||
|
|
||||||
if (((numplay == 0) || (numrec == 0)) && (numplay != numrec))
|
if (((numplay == 0) || (numrec == 0)) && (numplay != numrec))
|
||||||
@ -758,24 +757,25 @@ pcm_unregister(device_t dev)
|
|||||||
struct snddev_channel *sce;
|
struct snddev_channel *sce;
|
||||||
struct pcm_channel *ch;
|
struct pcm_channel *ch;
|
||||||
|
|
||||||
|
if (sndstat_acquire() != 0) {
|
||||||
|
device_printf(dev, "unregister: sndstat busy\n");
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
snd_mtxlock(d->lock);
|
snd_mtxlock(d->lock);
|
||||||
if (d->inprog) {
|
if (d->inprog) {
|
||||||
device_printf(dev, "unregister: operation in progress\n");
|
device_printf(dev, "unregister: operation in progress\n");
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
|
sndstat_release();
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
if (sndstat_busy() != 0) {
|
|
||||||
device_printf(dev, "unregister: sndstat busy\n");
|
|
||||||
snd_mtxunlock(d->lock);
|
|
||||||
return EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
ch = sce->channel;
|
ch = sce->channel;
|
||||||
if (ch->refcount > 0) {
|
if (ch->refcount > 0) {
|
||||||
device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid);
|
device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid);
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
|
sndstat_release();
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -783,6 +783,7 @@ pcm_unregister(device_t dev)
|
|||||||
if (mixer_uninit(dev)) {
|
if (mixer_uninit(dev)) {
|
||||||
device_printf(dev, "unregister: mixer busy\n");
|
device_printf(dev, "unregister: mixer busy\n");
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
|
sndstat_release();
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,9 +808,10 @@ pcm_unregister(device_t dev)
|
|||||||
chn_kill(d->fakechan);
|
chn_kill(d->fakechan);
|
||||||
fkchan_kill(d->fakechan);
|
fkchan_kill(d->fakechan);
|
||||||
|
|
||||||
sndstat_unregister(dev);
|
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
snd_mtxfree(d->lock);
|
snd_mtxfree(d->lock);
|
||||||
|
sndstat_unregister(dev);
|
||||||
|
sndstat_release();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,7 +907,8 @@ sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
|
|||||||
sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
|
sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
|
||||||
if (f->desc->type == FEEDER_RATE)
|
if (f->desc->type == FEEDER_RATE)
|
||||||
sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
|
sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
|
||||||
if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER)
|
if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER ||
|
||||||
|
f->desc->type == FEEDER_VOLUME)
|
||||||
sbuf_printf(s, "(0x%08x)", f->desc->out);
|
sbuf_printf(s, "(0x%08x)", f->desc->out);
|
||||||
sbuf_printf(s, " -> ");
|
sbuf_printf(s, " -> ");
|
||||||
f = f->parent;
|
f = f->parent;
|
||||||
|
@ -130,7 +130,8 @@ currently minor = (channel << 16) + (unit << 4) + dev
|
|||||||
#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
|
#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
|
||||||
|
|
||||||
#define SD_F_SIMPLEX 0x00000001
|
#define SD_F_SIMPLEX 0x00000001
|
||||||
#define SD_F_AUTOVCHAN 0x00000002
|
#define SD_F_AUTOVCHAN 0x00000002
|
||||||
|
#define SD_F_SOFTVOL 0x00000004
|
||||||
#define SD_F_PRIO_RD 0x10000000
|
#define SD_F_PRIO_RD 0x10000000
|
||||||
#define SD_F_PRIO_WR 0x20000000
|
#define SD_F_PRIO_WR 0x20000000
|
||||||
#define SD_F_PRIO_SET (SD_F_PRIO_RD | SD_F_PRIO_WR)
|
#define SD_F_PRIO_SET (SD_F_PRIO_RD | SD_F_PRIO_WR)
|
||||||
@ -238,11 +239,12 @@ void snd_mtxassert(void *m);
|
|||||||
int sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS);
|
int sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS);
|
||||||
|
|
||||||
typedef int (*sndstat_handler)(struct sbuf *s, device_t dev, int verbose);
|
typedef int (*sndstat_handler)(struct sbuf *s, device_t dev, int verbose);
|
||||||
|
int sndstat_acquire(void);
|
||||||
|
int sndstat_release(void);
|
||||||
int sndstat_register(device_t dev, char *str, sndstat_handler handler);
|
int sndstat_register(device_t dev, char *str, sndstat_handler handler);
|
||||||
int sndstat_registerfile(char *str);
|
int sndstat_registerfile(char *str);
|
||||||
int sndstat_unregister(device_t dev);
|
int sndstat_unregister(device_t dev);
|
||||||
int sndstat_unregisterfile(char *str);
|
int sndstat_unregisterfile(char *str);
|
||||||
int sndstat_busy(void);
|
|
||||||
|
|
||||||
#define SND_DECLARE_FILE(version) \
|
#define SND_DECLARE_FILE(version) \
|
||||||
_SND_DECLARE_FILE(__LINE__, version)
|
_SND_DECLARE_FILE(__LINE__, version)
|
||||||
|
Loading…
Reference in New Issue
Block a user