Module Name: src
Committed By: martin
Date: Thu Apr 30 16:05:18 UTC 2020
Modified Files:
src/sys/dev/audio [netbsd-9]: audio.c audiovar.h
Log Message:
Pull up following revision(s) (requested by isaki in ticket #877):
sys/dev/audio/audio.c: revision 1.55
sys/dev/audio/audio.c: revision 1.41
sys/dev/audio/audio.c: revision 1.48
sys/dev/audio/audiovar.h: revision 1.7
sys/dev/audio/audio.c: revision 1.63 (via patch)
sys/dev/audio/audiovar.h: revision 1.11
sys/dev/audio/audio.c: revision 1.64
Simplify async_mixer handling.
- It makes FIOASYNC code in mixer_ioctl() symmetric.
- For readability, mixer_async_{add,remove}() should take pid argument
though pid is always curproc.
hw_if->query_format is already mandatory method. Drop null checks.
Improve error handling around audio_hw_probe().
It was difficult to return multiple errors.
Split sc_lock and sc_exlock.
Most (probably all) malloc/free (or routines which may sleep) now can be
called without holding mutex.
Pointed out by riastradh@.
Fix/Update comments about allocm/freem.
To generate a diff of this commit:
cvs rdiff -u -r1.28.2.11 -r1.28.2.12 src/sys/dev/audio/audio.c
cvs rdiff -u -r1.4.2.2 -r1.4.2.3 src/sys/dev/audio/audiovar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/audio/audio.c
diff -u src/sys/dev/audio/audio.c:1.28.2.11 src/sys/dev/audio/audio.c:1.28.2.12
--- src/sys/dev/audio/audio.c:1.28.2.11 Thu Apr 30 15:43:30 2020
+++ src/sys/dev/audio/audio.c Thu Apr 30 16:05:18 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: audio.c,v 1.28.2.11 2020/04/30 15:43:30 martin Exp $ */
+/* $NetBSD: audio.c,v 1.28.2.12 2020/04/30 16:05:18 martin Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -118,8 +118,8 @@
* set_port - x +
* get_port - x +
* query_devinfo - x
- * allocm - - + (*1)
- * freem - - + (*1)
+ * allocm - - +
+ * freem - - +
* round_buffersize - x
* get_props - x Called at attach time
* trigger_output x x +
@@ -127,10 +127,6 @@
* dev_ioctl - x
* get_locks - - Called at attach time
*
- * *1 Note: Before 8.0, since these have been called only at attach time,
- * neither lock were necessary. Currently, on the other hand, since
- * these may be also called after attach, the thread lock is required.
- *
* In addition, there is an additional lock.
*
* - track->lock. This is an atomic variable and is similar to the
@@ -142,7 +138,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.11 2020/04/30 15:43:30 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.12 2020/04/30 16:05:18 martin Exp $");
#ifdef _KERNEL_OPT
#include "audio.h"
@@ -466,6 +462,9 @@ audio_track_bufstat(audio_track_t *track
int audio_idle_timeout = 30;
#endif
+/* Number of elements of async mixer's pid */
+#define AM_CAPACITY (4)
+
struct portname {
const char *name;
int mask;
@@ -497,8 +496,10 @@ static void audio_mixer_restore(struct a
static void audio_softintr_rd(void *);
static void audio_softintr_wr(void *);
-static int audio_enter_exclusive(struct audio_softc *);
-static void audio_exit_exclusive(struct audio_softc *);
+static int audio_exlock_mutex_enter(struct audio_softc *);
+static void audio_exlock_mutex_exit(struct audio_softc *);
+static int audio_exlock_enter(struct audio_softc *);
+static void audio_exlock_exit(struct audio_softc *);
static struct audio_softc *audio_file_enter(audio_file_t *, struct psref *);
static void audio_file_exit(struct audio_softc *, struct psref *);
static int audio_track_waitio(struct audio_softc *, audio_track_t *);
@@ -560,9 +561,7 @@ static int audio_mixers_init(struct audi
const audio_format2_t *, const audio_format2_t *,
const audio_filter_reg_t *, const audio_filter_reg_t *);
static int audio_select_freq(const struct audio_format *);
-static int audio_hw_probe(struct audio_softc *, int, int *,
- audio_format2_t *, audio_format2_t *);
-static int audio_hw_probe_fmt(struct audio_softc *, audio_format2_t *, int);
+static int audio_hw_probe(struct audio_softc *, audio_format2_t *, int);
static int audio_hw_validate_format(struct audio_softc *, int,
const audio_format2_t *);
static int audio_mixers_set_format(struct audio_softc *,
@@ -609,7 +608,8 @@ static void mixer_init(struct audio_soft
static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *);
static int mixer_close(struct audio_softc *, audio_file_t *);
static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *);
-static void mixer_remove(struct audio_softc *);
+static void mixer_async_add(struct audio_softc *, pid_t);
+static void mixer_async_remove(struct audio_softc *, pid_t);
static void mixer_signal(struct audio_softc *);
static int au_portof(struct audio_softc *, char *, int);
@@ -882,9 +882,13 @@ audioattach(device_t parent, device_t se
sc->hw_hdl = hdlp;
sc->hw_dev = parent;
+ sc->sc_exlock = 1;
sc->sc_blk_ms = AUDIO_BLK_MS;
SLIST_INIT(&sc->sc_files);
cv_init(&sc->sc_exlockcv, "audiolk");
+ sc->sc_am_capacity = 0;
+ sc->sc_am_used = 0;
+ sc->sc_am = NULL;
mutex_enter(sc->sc_lock);
sc->sc_props = hw_if->get_props(sc->hw_hdl);
@@ -932,24 +936,47 @@ audioattach(device_t parent, device_t se
memset(&rhwfmt, 0, sizeof(rhwfmt));
memset(&pfil, 0, sizeof(pfil));
memset(&rfil, 0, sizeof(rfil));
- mutex_enter(sc->sc_lock);
- error = audio_hw_probe(sc, has_indep, &mode, &phwfmt, &rhwfmt);
- if (error) {
- mutex_exit(sc->sc_lock);
- aprint_error_dev(self, "audio_hw_probe failed, "
- "error = %d\n", error);
- goto bad;
- }
- if (mode == 0) {
- mutex_exit(sc->sc_lock);
- aprint_error_dev(self, "audio_hw_probe failed, no mode\n");
- goto bad;
+ if (has_indep) {
+ int perror, rerror;
+
+ /* On independent devices, probe separately. */
+ perror = audio_hw_probe(sc, &phwfmt, AUMODE_PLAY);
+ rerror = audio_hw_probe(sc, &rhwfmt, AUMODE_RECORD);
+ if (perror && rerror) {
+ aprint_error_dev(self, "audio_hw_probe failed, "
+ "perror = %d, rerror = %d\n", perror, rerror);
+ goto bad;
+ }
+ if (perror) {
+ mode &= ~AUMODE_PLAY;
+ aprint_error_dev(self, "audio_hw_probe failed with "
+ "%d, playback disabled\n", perror);
+ }
+ if (rerror) {
+ mode &= ~AUMODE_RECORD;
+ aprint_error_dev(self, "audio_hw_probe failed with "
+ "%d, capture disabled\n", rerror);
+ }
+ } else {
+ /*
+ * On non independent devices or uni-directional devices,
+ * probe once (simultaneously).
+ */
+ audio_format2_t *fmt = has_playback ? &phwfmt : &rhwfmt;
+ error = audio_hw_probe(sc, fmt, mode);
+ if (error) {
+ aprint_error_dev(self, "audio_hw_probe failed, "
+ "error = %d\n", error);
+ goto bad;
+ }
+ if (has_playback && has_capture)
+ rhwfmt = phwfmt;
}
+
/* Init hardware. */
/* hw_probe() also validates [pr]hwfmt. */
error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil);
if (error) {
- mutex_exit(sc->sc_lock);
aprint_error_dev(self, "audio_hw_set_format failed, "
"error = %d\n", error);
goto bad;
@@ -960,7 +987,6 @@ audioattach(device_t parent, device_t se
* attach time, we assume a success.
*/
error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil);
- mutex_exit(sc->sc_lock);
if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) {
aprint_error_dev(self, "audio_mixers_init failed, "
"error = %d\n", error);
@@ -1052,11 +1078,13 @@ audioattach(device_t parent, device_t se
#endif
audiorescan(self, "audio", NULL);
+ sc->sc_exlock = 0;
return;
bad:
/* Clearing hw_if means that device is attached but disabled. */
sc->hw_if = NULL;
+ sc->sc_exlock = 0;
aprint_error_dev(sc->sc_dev, "disabled\n");
return;
}
@@ -1274,6 +1302,7 @@ audiodetach(device_t self, int flags)
* that hold sc, and any new calls with files that were for sc will
* fail. Thus, we now have exclusive access to the softc.
*/
+ sc->sc_exlock = 1;
/*
* Nuke all open instances.
@@ -1299,7 +1328,6 @@ audiodetach(device_t self, int flags)
pmf_device_deregister(self);
/* Free resources */
- mutex_enter(sc->sc_lock);
if (sc->sc_pmixer) {
audio_mixer_destroy(sc, sc->sc_pmixer);
kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer));
@@ -1308,7 +1336,8 @@ audiodetach(device_t self, int flags)
audio_mixer_destroy(sc, sc->sc_rmixer);
kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer));
}
- mutex_exit(sc->sc_lock);
+ if (sc->sc_am)
+ kern_free(sc->sc_am);
seldestroy(&sc->sc_wsel);
seldestroy(&sc->sc_rsel);
@@ -1378,12 +1407,12 @@ audio_attach_mi(const struct audio_hw_if
}
/*
- * Acquire sc_lock and enter exlock critical section.
- * If successful, it returns 0. Otherwise returns errno.
+ * Enter critical section and also keep sc_lock.
+ * If successful, returns 0 with sc_lock held. Otherwise returns errno.
* Must be called without sc_lock held.
*/
static int
-audio_enter_exclusive(struct audio_softc *sc)
+audio_exlock_mutex_enter(struct audio_softc *sc)
{
int error;
@@ -1409,23 +1438,51 @@ audio_enter_exclusive(struct audio_softc
}
/*
- * Leave exlock critical section and release sc_lock.
+ * Exit critical section and exit sc_lock.
* Must be called with sc_lock held.
*/
static void
-audio_exit_exclusive(struct audio_softc *sc)
+audio_exlock_mutex_exit(struct audio_softc *sc)
{
KASSERT(mutex_owned(sc->sc_lock));
- KASSERT(sc->sc_exlock);
- /* Leave critical section */
sc->sc_exlock = 0;
cv_broadcast(&sc->sc_exlockcv);
mutex_exit(sc->sc_lock);
}
/*
+ * Enter critical section.
+ * If successful, it returns 0. Otherwise returns errno.
+ * Must be called without sc_lock held.
+ * This function returns without sc_lock held.
+ */
+static int
+audio_exlock_enter(struct audio_softc *sc)
+{
+ int error;
+
+ error = audio_exlock_mutex_enter(sc);
+ if (error)
+ return error;
+ mutex_exit(sc->sc_lock);
+ return 0;
+}
+
+/*
+ * Exit critical section.
+ * Must be called without sc_lock held.
+ */
+static void
+audio_exlock_exit(struct audio_softc *sc)
+{
+
+ mutex_enter(sc->sc_lock);
+ audio_exlock_mutex_exit(sc);
+}
+
+/*
* Acquire sc from file, and increment the psref count.
* If successful, returns sc. Otherwise returns NULL.
*/
@@ -1539,7 +1596,7 @@ audioopen(dev_t dev, int flags, int ifmt
if (sc == NULL || sc->hw_if == NULL)
return ENXIO;
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_enter(sc);
if (error)
return error;
@@ -1559,7 +1616,7 @@ audioopen(dev_t dev, int flags, int ifmt
error = ENXIO;
break;
}
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
return error;
}
@@ -1893,14 +1950,14 @@ audiobellopen(dev_t dev, audio_file_t **
if (sc == NULL || sc->hw_if == NULL)
return ENXIO;
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_enter(sc);
if (error)
return error;
device_active(sc->sc_dev, DVA_SYSTEM);
error = audio_open(dev, sc, FWRITE, 0, curlwp, filep);
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
return error;
}
@@ -1943,11 +2000,11 @@ audiobellsetrate(audio_file_t *file, u_i
AUDIO_INITINFO(&ai);
ai.play.sample_rate = sample_rate;
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_enter(sc);
if (error)
goto done;
error = audio_file_setinfo(sc, file, &ai);
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
done:
audio_file_exit(sc, &sc_ref);
@@ -1976,6 +2033,10 @@ audiobellwrite(audio_file_t *file, struc
/*
* Audio driver
*/
+
+/*
+ * Must be called with sc_exlock held and without sc_lock held.
+ */
int
audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
struct lwp *l, audio_file_t **bellfile)
@@ -1988,7 +2049,6 @@ audio_open(dev_t dev, struct audio_softc
int fd;
int error;
- KASSERT(mutex_owned(sc->sc_lock));
KASSERT(sc->sc_exlock);
TRACE(1, "%sdev=%s flags=0x%x po=%d ro=%d",
@@ -2110,9 +2170,11 @@ audio_open(dev_t dev, struct audio_softc
hwflags |= FREAD;
}
+ mutex_enter(sc->sc_lock);
mutex_enter(sc->sc_intr_lock);
error = sc->hw_if->open(sc->hw_hdl, hwflags);
mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
if (error)
goto bad2;
}
@@ -2129,9 +2191,11 @@ audio_open(dev_t dev, struct audio_softc
} else {
on = 0;
}
+ mutex_enter(sc->sc_lock);
mutex_enter(sc->sc_intr_lock);
error = sc->hw_if->speaker_ctl(sc->hw_hdl, on);
mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
if (error)
goto bad3;
}
@@ -2148,12 +2212,14 @@ audio_open(dev_t dev, struct audio_softc
if (af->ptrack && sc->sc_popens == 0) {
if (sc->hw_if->init_output) {
hwbuf = &sc->sc_pmixer->hwbuf;
+ mutex_enter(sc->sc_lock);
mutex_enter(sc->sc_intr_lock);
error = sc->hw_if->init_output(sc->hw_hdl,
hwbuf->mem,
hwbuf->capacity *
hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY);
mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
if (error)
goto bad3;
}
@@ -2162,12 +2228,14 @@ audio_open(dev_t dev, struct audio_softc
if (af->rtrack && sc->sc_ropens == 0) {
if (sc->hw_if->init_input) {
hwbuf = &sc->sc_rmixer->hwbuf;
+ mutex_enter(sc->sc_lock);
mutex_enter(sc->sc_intr_lock);
error = sc->hw_if->init_input(sc->hw_hdl,
hwbuf->mem,
hwbuf->capacity *
hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY);
mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
if (error)
goto bad3;
}
@@ -2183,6 +2251,7 @@ audio_open(dev_t dev, struct audio_softc
* Count up finally.
* Don't fail from here.
*/
+ mutex_enter(sc->sc_lock);
if (af->ptrack)
sc->sc_popens++;
if (af->rtrack)
@@ -2190,6 +2259,7 @@ audio_open(dev_t dev, struct audio_softc
mutex_enter(sc->sc_intr_lock);
SLIST_INSERT_HEAD(&sc->sc_files, af, entry);
mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
if (bellfile) {
*bellfile = af;
@@ -2208,9 +2278,11 @@ audio_open(dev_t dev, struct audio_softc
bad3:
if (sc->sc_popens + sc->sc_ropens == 0) {
if (sc->hw_if->close) {
+ mutex_enter(sc->sc_lock);
mutex_enter(sc->sc_intr_lock);
sc->hw_if->close(sc->hw_hdl);
mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
}
}
bad2:
@@ -2239,7 +2311,7 @@ audio_close(struct audio_softc *sc, audi
/*
* Drain first.
- * It must be done before unlinking(acquiring exclusive lock).
+ * It must be done before unlinking(acquiring exlock).
*/
if (file->ptrack) {
mutex_enter(sc->sc_lock);
@@ -2259,6 +2331,8 @@ audio_unlink(struct audio_softc *sc, aud
{
int error;
+ mutex_enter(sc->sc_lock);
+
TRACEF(1, file, "%spid=%d.%d po=%d ro=%d",
(audiodebug >= 3) ? "start " : "",
(int)curproc->p_pid, (int)curlwp->l_lid,
@@ -2267,10 +2341,9 @@ audio_unlink(struct audio_softc *sc, aud
"sc->sc_popens=%d, sc->sc_ropens=%d",
sc->sc_popens, sc->sc_ropens);
- mutex_enter(sc->sc_lock);
/*
- * Acquire exclusive lock to protect counters.
- * Does not use audio_enter_exclusive() due to sc_dying.
+ * Acquire exlock to protect counters.
+ * Does not use audio_exlock_enter() due to sc_dying.
*/
while (__predict_false(sc->sc_exlock != 0)) {
error = cv_timedwait_sig(&sc->sc_exlockcv, sc->sc_lock,
@@ -2344,12 +2417,14 @@ audio_unlink(struct audio_softc *sc, aud
sc->hw_if->close(sc->hw_hdl);
mutex_exit(sc->sc_intr_lock);
}
+ }
+ mutex_exit(sc->sc_lock);
+ if (sc->sc_popens + sc->sc_ropens == 0)
kauth_cred_free(sc->sc_cred);
- }
TRACE(3, "done");
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
return 0;
}
@@ -2382,27 +2457,26 @@ audio_read(struct audio_softc *sc, struc
TRACET(2, track, "resid=%zd", uio->uio_resid);
+ error = audio_exlock_mutex_enter(sc);
+ if (error)
+ return error;
+
#ifdef AUDIO_PM_IDLE
- mutex_enter(sc->sc_lock);
if (device_is_active(&sc->sc_dev) || sc->sc_idle)
device_active(&sc->sc_dev, DVA_SYSTEM);
- mutex_exit(sc->sc_lock);
#endif
- usrbuf = &track->usrbuf;
- input = track->input;
-
/*
* The first read starts rmixer.
*/
- error = audio_enter_exclusive(sc);
- if (error)
- return error;
if (sc->sc_rbusy == false)
audio_rmixer_start(sc);
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
+ usrbuf = &track->usrbuf;
+ input = track->input;
error = 0;
+
while (uio->uio_resid > 0 && error == 0) {
int bytes;
@@ -2510,28 +2584,27 @@ audio_write(struct audio_softc *sc, stru
return 0;
}
+ error = audio_exlock_mutex_enter(sc);
+ if (error)
+ return error;
+
#ifdef AUDIO_PM_IDLE
- mutex_enter(sc->sc_lock);
if (device_is_active(&sc->sc_dev) || sc->sc_idle)
device_active(&sc->sc_dev, DVA_SYSTEM);
- mutex_exit(sc->sc_lock);
#endif
- usrbuf = &track->usrbuf;
- outbuf = &track->outbuf;
-
/*
* The first write starts pmixer.
*/
- error = audio_enter_exclusive(sc);
- if (error)
- return error;
if (sc->sc_pbusy == false)
audio_pmixer_start(sc, false);
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
+ usrbuf = &track->usrbuf;
+ outbuf = &track->outbuf;
track->pstate = AUDIO_STATE_RUNNING;
error = 0;
+
while (uio->uio_resid > 0 && error == 0) {
int bytes;
@@ -2760,32 +2833,34 @@ audio_ioctl(dev_t dev, struct audio_soft
break;
case AUDIO_SETINFO:
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_enter(sc);
if (error)
break;
error = audio_file_setinfo(sc, file, (struct audio_info *)addr);
if (error) {
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
break;
}
/* XXX TODO: update last_ai if /dev/sound ? */
if (ISDEVSOUND(dev))
error = audiogetinfo(sc, &sc->sc_ai, 0, file);
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
break;
case AUDIO_GETINFO:
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_enter(sc);
if (error)
break;
error = audiogetinfo(sc, (struct audio_info *)addr, 1, file);
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
break;
case AUDIO_GETBUFINFO:
- mutex_enter(sc->sc_lock);
+ error = audio_exlock_enter(sc);
+ if (error)
+ break;
error = audiogetinfo(sc, (struct audio_info *)addr, 0, file);
- mutex_exit(sc->sc_lock);
+ audio_exlock_exit(sc);
break;
case AUDIO_DRAIN:
@@ -2828,10 +2903,12 @@ audio_ioctl(dev_t dev, struct audio_soft
* If HW has full duplex mode and there are two mixers,
* it is full duplex. Otherwise half duplex.
*/
- mutex_enter(sc->sc_lock);
+ error = audio_exlock_enter(sc);
+ if (error)
+ break;
fd = (sc->sc_props & AUDIO_PROP_FULLDUPLEX)
&& (sc->sc_pmixer && sc->sc_rmixer);
- mutex_exit(sc->sc_lock);
+ audio_exlock_exit(sc);
*(int *)addr = fd;
break;
@@ -2841,30 +2918,30 @@ audio_ioctl(dev_t dev, struct audio_soft
case AUDIO_QUERYFORMAT:
query = (audio_format_query_t *)addr;
- if (sc->hw_if->query_format) {
- mutex_enter(sc->sc_lock);
- error = sc->hw_if->query_format(sc->hw_hdl, query);
- mutex_exit(sc->sc_lock);
- /* Hide internal infomations */
- query->fmt.driver_data = NULL;
- } else {
- error = ENODEV;
- }
+ mutex_enter(sc->sc_lock);
+ error = sc->hw_if->query_format(sc->hw_hdl, query);
+ mutex_exit(sc->sc_lock);
+ /* Hide internal infomations */
+ query->fmt.driver_data = NULL;
break;
case AUDIO_GETFORMAT:
+ error = audio_exlock_enter(sc);
+ if (error)
+ break;
audio_mixers_get_format(sc, (struct audio_info *)addr);
+ audio_exlock_exit(sc);
break;
case AUDIO_SETFORMAT:
- mutex_enter(sc->sc_lock);
+ error = audio_exlock_enter(sc);
audio_mixers_get_format(sc, &ai);
error = audio_mixers_set_format(sc, (struct audio_info *)addr);
if (error) {
/* Rollback */
audio_mixers_set_format(sc, &ai);
}
- mutex_exit(sc->sc_lock);
+ audio_exlock_exit(sc);
break;
case AUDIO_SETFD:
@@ -2875,12 +2952,10 @@ audio_ioctl(dev_t dev, struct audio_soft
default:
if (sc->hw_if->dev_ioctl) {
- error = audio_enter_exclusive(sc);
- if (error)
- break;
+ mutex_enter(sc->sc_lock);
error = sc->hw_if->dev_ioctl(sc->hw_hdl,
cmd, addr, flag, l);
- audio_exit_exclusive(sc);
+ mutex_exit(sc->sc_lock);
} else {
TRACEF(2, file, "unknown ioctl");
error = EINVAL;
@@ -3083,6 +3158,7 @@ audio_kqfilter(struct audio_softc *sc, a
TRACEF(3, file, "kn=%p kn_filter=%x", kn, (int)kn->kn_filter);
+ mutex_enter(sc->sc_lock);
switch (kn->kn_filter) {
case EVFILT_READ:
klist = &sc->sc_rsel.sel_klist;
@@ -3095,12 +3171,12 @@ audio_kqfilter(struct audio_softc *sc, a
break;
default:
+ mutex_exit(sc->sc_lock);
return EINVAL;
}
kn->kn_hook = file;
- mutex_enter(sc->sc_lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
mutex_exit(sc->sc_lock);
@@ -3161,12 +3237,12 @@ audio_mmap(struct audio_softc *sc, off_t
track->mmapped = true;
if (!track->is_pause) {
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_mutex_enter(sc);
if (error)
return error;
if (sc->sc_pbusy == false)
audio_pmixer_start(sc, true);
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
}
/* XXX mmapping record buffer is not supported */
}
@@ -3185,6 +3261,7 @@ audio_mmap(struct audio_softc *sc, off_t
/*
* /dev/audioctl has to be able to open at any time without interference
* with any /dev/audio or /dev/sound.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static int
audioctl_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
@@ -3195,7 +3272,6 @@ audioctl_open(dev_t dev, struct audio_so
int fd;
int error;
- KASSERT(mutex_owned(sc->sc_lock));
KASSERT(sc->sc_exlock);
TRACE(1, "");
@@ -3686,6 +3762,7 @@ audio_track_freq_down(audio_filter_arg_t
/*
* Creates track and returns it.
+ * Must be called without sc_lock held.
*/
audio_track_t *
audio_track_create(struct audio_softc *sc, audio_trackmixer_t *mixer)
@@ -4658,7 +4735,7 @@ audio_track_record(audio_track_t *track)
/*
* Calcurate blktime [msec] from mixer(.hwbuf.fmt).
- * Must be called with sc_lock held.
+ * Must be called with sc_exlock held.
*/
static u_int
audio_mixer_calc_blktime(struct audio_softc *sc, audio_trackmixer_t *mixer)
@@ -4667,7 +4744,7 @@ audio_mixer_calc_blktime(struct audio_so
u_int blktime;
u_int frames_per_block;
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock);
fmt = &mixer->hwbuf.fmt;
blktime = sc->sc_blk_ms;
@@ -4695,7 +4772,7 @@ audio_mixer_calc_blktime(struct audio_so
* Set AUMODE_PLAY to the 'mode' for playback or AUMODE_RECORD for recording.
* sc->sc_[pr]mixer (corresponding to the 'mode') must be zero-filled.
* This function returns 0 on sucessful. Otherwise returns errno.
- * Must be called with sc_lock held.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static int
audio_mixer_init(struct audio_softc *sc, int mode,
@@ -4714,7 +4791,7 @@ audio_mixer_init(struct audio_softc *sc,
KASSERT(hwfmt != NULL);
KASSERT(reg != NULL);
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock);
error = 0;
if (mode == AUMODE_PLAY)
@@ -4737,8 +4814,10 @@ audio_mixer_init(struct audio_softc *sc,
if (sc->hw_if->round_blocksize) {
int rounded;
audio_params_t p = format2_to_params(&mixer->hwbuf.fmt);
+ mutex_enter(sc->sc_lock);
rounded = sc->hw_if->round_blocksize(sc->hw_hdl, blksize,
mode, &p);
+ mutex_exit(sc->sc_lock);
TRACE(1, "round_blocksize %d -> %d", blksize, rounded);
if (rounded != blksize) {
if ((rounded * NBBY) % (mixer->hwbuf.fmt.stride *
@@ -4762,8 +4841,10 @@ audio_mixer_init(struct audio_softc *sc,
bufsize = frametobyte(&mixer->hwbuf.fmt, capacity);
if (sc->hw_if->round_buffersize) {
size_t rounded;
+ mutex_enter(sc->sc_lock);
rounded = sc->hw_if->round_buffersize(sc->hw_hdl, mode,
bufsize);
+ mutex_exit(sc->sc_lock);
TRACE(1, "round_buffersize %zd -> %zd", bufsize, rounded);
if (rounded < bufsize) {
/* buffersize needs NBLKHW blocks at least. */
@@ -4792,10 +4873,8 @@ audio_mixer_init(struct audio_softc *sc,
bufsize);
mixer->hwbuf.capacity = capacity;
- /*
- * XXX need to release sc_lock for compatibility?
- */
if (sc->hw_if->allocm) {
+ /* sc_lock is not necessary for allocm */
mixer->hwbuf.mem = sc->hw_if->allocm(sc->hw_hdl, mode, bufsize);
if (mixer->hwbuf.mem == NULL) {
device_printf(sc->sc_dev, "%s: allocm(%zu) failed\n",
@@ -4901,19 +4980,20 @@ abort:
/*
* Releases all resources of 'mixer'.
* Note that it does not release the memory area of 'mixer' itself.
- * Must be called with sc_lock held.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static void
audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer)
{
int bufsize;
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock == 1);
bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity);
if (mixer->hwbuf.mem != NULL) {
if (sc->hw_if->freem) {
+ /* sc_lock is not necessary for freem */
sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize);
} else {
kmem_free(mixer->hwbuf.mem, bufsize);
@@ -5849,31 +5929,24 @@ audio_track_drain(struct audio_softc *sc
/*
* Send signal to process.
* This is intended to be called only from audio_softintr_{rd,wr}.
- * Must be called with sc_lock && sc_intr_lock held.
+ * Must be called without sc_intr_lock held.
*/
static inline void
audio_psignal(struct audio_softc *sc, pid_t pid, int signum)
{
proc_t *p;
- KASSERT(mutex_owned(sc->sc_lock));
- KASSERT(mutex_owned(sc->sc_intr_lock));
KASSERT(pid != 0);
/*
* psignal() must be called without spin lock held.
- * So leave intr_lock temporarily here.
*/
- mutex_exit(sc->sc_intr_lock);
mutex_enter(proc_lock);
p = proc_find(pid);
if (p)
psignal(p, signum);
mutex_exit(proc_lock);
-
- /* Enter intr_lock again */
- mutex_enter(sc->sc_intr_lock);
}
/*
@@ -5897,7 +5970,6 @@ audio_softintr_rd(void *cookie)
pid_t pid;
mutex_enter(sc->sc_lock);
- mutex_enter(sc->sc_intr_lock);
SLIST_FOREACH(f, &sc->sc_files, entry) {
audio_track_t *track = f->rtrack;
@@ -5916,7 +5988,6 @@ audio_softintr_rd(void *cookie)
audio_psignal(sc, pid, SIGIO);
}
}
- mutex_exit(sc->sc_intr_lock);
/* Notify that data has arrived. */
selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT);
@@ -5948,7 +6019,6 @@ audio_softintr_wr(void *cookie)
found = false;
mutex_enter(sc->sc_lock);
- mutex_enter(sc->sc_intr_lock);
SLIST_FOREACH(f, &sc->sc_files, entry) {
audio_track_t *track = f->ptrack;
@@ -5978,7 +6048,6 @@ audio_softintr_wr(void *cookie)
}
}
}
- mutex_exit(sc->sc_intr_lock);
/*
* Notify for select/poll when someone become writable.
@@ -6082,7 +6151,7 @@ audio_check_params(audio_format2_t *p)
* phwfmt and rhwfmt indicate the hardware format. pfil and rfil indicate
* the filter registration information. These four must not be NULL.
* If successful returns 0. Otherwise returns errno.
- * Must be called with sc_lock held.
+ * Must be called with sc_exlock held and without sc_lock held.
* Must not be called if there are any tracks.
* Caller should check that the initialization succeed by whether
* sc_[pr]mixer is not NULL.
@@ -6098,7 +6167,7 @@ audio_mixers_init(struct audio_softc *sc
KASSERT(rhwfmt != NULL);
KASSERT(pfil != NULL);
KASSERT(rfil != NULL);
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock);
if ((mode & AUMODE_PLAY)) {
if (sc->sc_pmixer == NULL) {
@@ -6185,68 +6254,13 @@ audio_select_freq(const struct audio_for
}
/*
- * Probe playback and/or recording format (depending on *modep).
- * *modep is an in-out parameter. It indicates the direction to configure
- * as an argument, and the direction configured is written back as out
- * parameter.
- * If successful, probed hardware format is stored into *phwfmt, *rhwfmt
- * depending on *modep, and return 0. Otherwise it returns errno.
- * Must be called with sc_lock held.
- */
-static int
-audio_hw_probe(struct audio_softc *sc, int is_indep, int *modep,
- audio_format2_t *phwfmt, audio_format2_t *rhwfmt)
-{
- audio_format2_t fmt;
- int mode;
- int error = 0;
-
- KASSERT(mutex_owned(sc->sc_lock));
-
- mode = *modep;
- KASSERTMSG((mode & (AUMODE_PLAY | AUMODE_RECORD)) != 0, "mode=0x%x", mode);
-
- if (is_indep) {
- int errorp = 0, errorr = 0;
-
- /* On independent devices, probe separately. */
- if ((mode & AUMODE_PLAY) != 0) {
- errorp = audio_hw_probe_fmt(sc, phwfmt, AUMODE_PLAY);
- if (errorp)
- mode &= ~AUMODE_PLAY;
- }
- if ((mode & AUMODE_RECORD) != 0) {
- errorr = audio_hw_probe_fmt(sc, rhwfmt, AUMODE_RECORD);
- if (errorr)
- mode &= ~AUMODE_RECORD;
- }
-
- /* Return error if both play and record probes failed. */
- if (errorp && errorr)
- error = errorp;
- } else {
- /* On non independent devices, probe simultaneously. */
- error = audio_hw_probe_fmt(sc, &fmt, mode);
- if (error) {
- mode = 0;
- } else {
- *phwfmt = fmt;
- *rhwfmt = fmt;
- }
- }
-
- *modep = mode;
- return error;
-}
-
-/*
* Choose the most preferred hardware format.
* If successful, it will store the chosen format into *cand and return 0.
* Otherwise, return errno.
- * Must be called with sc_lock held.
+ * Must be called without sc_lock held.
*/
static int
-audio_hw_probe_fmt(struct audio_softc *sc, audio_format2_t *cand, int mode)
+audio_hw_probe(struct audio_softc *sc, audio_format2_t *cand, int mode)
{
audio_format_query_t query;
int cand_score;
@@ -6254,8 +6268,6 @@ audio_hw_probe_fmt(struct audio_softc *s
int i;
int error;
- KASSERT(mutex_owned(sc->sc_lock));
-
/*
* Score each formats and choose the highest one.
*
@@ -6270,7 +6282,9 @@ audio_hw_probe_fmt(struct audio_softc *s
memset(&query, 0, sizeof(query));
query.index = i;
+ mutex_enter(sc->sc_lock);
error = sc->hw_if->query_format(sc->hw_hdl, &query);
+ mutex_exit(sc->sc_lock);
if (error == EINVAL)
break;
if (error)
@@ -6358,7 +6372,7 @@ audio_hw_probe_fmt(struct audio_softc *s
* Validate fmt with query_format.
* If fmt is included in the result of query_format, returns 0.
* Otherwise returns EINVAL.
- * Must be called with sc_lock held.
+ * Must be called without sc_lock held.
*/
static int
audio_hw_validate_format(struct audio_softc *sc, int mode,
@@ -6370,26 +6384,11 @@ audio_hw_validate_format(struct audio_so
int error;
int j;
- KASSERT(mutex_owned(sc->sc_lock));
-
- /*
- * If query_format is not supported by hardware driver,
- * a rough check instead will be performed.
- * XXX This will gone in the future.
- */
- if (sc->hw_if->query_format == NULL) {
- if (fmt->encoding != AUDIO_ENCODING_SLINEAR_NE)
- return EINVAL;
- if (fmt->precision != AUDIO_INTERNAL_BITS)
- return EINVAL;
- if (fmt->stride != AUDIO_INTERNAL_BITS)
- return EINVAL;
- return 0;
- }
-
for (index = 0; ; index++) {
query.index = index;
+ mutex_enter(sc->sc_lock);
error = sc->hw_if->query_format(sc->hw_hdl, &query);
+ mutex_exit(sc->sc_lock);
if (error == EINVAL)
break;
if (error)
@@ -6446,7 +6445,7 @@ audio_hw_validate_format(struct audio_so
* All other fields in ai are ignored.
* If successful returns 0. Otherwise returns errno.
* This function does not roll back even if it fails.
- * Must be called with sc_lock held.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static int
audio_mixers_set_format(struct audio_softc *sc, const struct audio_info *ai)
@@ -6458,7 +6457,7 @@ audio_mixers_set_format(struct audio_sof
int mode;
int error;
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock);
/*
* Even when setting either one of playback and recording,
@@ -6563,10 +6562,14 @@ audio_mixers_set_format(struct audio_sof
/*
* Store current mixers format into *ai.
+ * Must be called with sc_exlock held.
*/
static void
audio_mixers_get_format(struct audio_softc *sc, struct audio_info *ai)
{
+
+ KASSERT(sc->sc_exlock);
+
/*
* There is no stride information in audio_info but it doesn't matter.
* trackmixer always treats stride and precision as the same.
@@ -6678,7 +6681,7 @@ audio_mixers_get_format(struct audio_sof
/*
* Set both track's parameters within a file depending on ai.
* Update sc_sound_[pr]* if set.
- * Must be called with sc_lock and sc_exlock held.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static int
audio_file_setinfo(struct audio_softc *sc, audio_file_t *file,
@@ -6698,7 +6701,6 @@ audio_file_setinfo(struct audio_softc *s
audio_format2_t saved_rfmt;
int error;
- KASSERT(mutex_owned(sc->sc_lock));
KASSERT(sc->sc_exlock);
pi = &ai->play;
@@ -6885,7 +6887,9 @@ audio_file_setinfo(struct audio_softc *s
}
/* Set mixer parameters */
+ mutex_enter(sc->sc_lock);
error = audio_hw_setinfo(sc, ai, &saved_ai);
+ mutex_exit(sc->sc_lock);
if (error)
goto abort1;
@@ -6959,7 +6963,9 @@ abort2:
sc->sc_sound_pparams = saved_pfmt;
file->mode = saved_ai.mode;
abort1:
+ mutex_enter(sc->sc_lock);
audio_hw_setinfo(sc, &saved_ai, NULL);
+ mutex_exit(sc->sc_lock);
return error;
}
@@ -7070,7 +7076,7 @@ audio_track_setinfo_water(audio_track_t
* The parameters handled here are *.port, *.gain, *.balance and monitor_gain.
* If oldai is specified, previous parameters are stored.
* This function itself does not roll back if error occurred.
- * Must be called with sc_lock and sc_exlock held.
+ * Must be called with sc_lock && sc_exlock held.
*/
static int
audio_hw_setinfo(struct audio_softc *sc, const struct audio_info *newai,
@@ -7220,7 +7226,7 @@ abort:
* - pfil, rfil will be filled with filter information specified by the
* hardware driver.
* and then returns 0. Otherwise returns errno.
- * Must be called with sc_lock held.
+ * Must be called without sc_lock held.
*/
static int
audio_hw_set_format(struct audio_softc *sc, int setmode,
@@ -7230,16 +7236,17 @@ audio_hw_set_format(struct audio_softc *
audio_params_t pp, rp;
int error;
- KASSERT(mutex_owned(sc->sc_lock));
KASSERT(phwfmt != NULL);
KASSERT(rhwfmt != NULL);
pp = format2_to_params(phwfmt);
rp = format2_to_params(rhwfmt);
+ mutex_enter(sc->sc_lock);
error = sc->hw_if->set_format(sc->hw_hdl, setmode,
&pp, &rp, pfil, rfil);
if (error) {
+ mutex_exit(sc->sc_lock);
device_printf(sc->sc_dev,
"set_format failed with %d\n", error);
return error;
@@ -7248,11 +7255,13 @@ audio_hw_set_format(struct audio_softc *
if (sc->hw_if->commit_settings) {
error = sc->hw_if->commit_settings(sc->hw_hdl);
if (error) {
+ mutex_exit(sc->sc_lock);
device_printf(sc->sc_dev,
"commit_settings failed with %d\n", error);
return error;
}
}
+ mutex_exit(sc->sc_lock);
return 0;
}
@@ -7260,9 +7269,7 @@ audio_hw_set_format(struct audio_softc *
/*
* Fill audio_info structure. If need_mixerinfo is true, it will also
* fill the hardware mixer information.
- * Must be called with sc_lock held.
- * Must be called with sc_exlock held, in addition, if need_mixerinfo is
- * true.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static int
audiogetinfo(struct audio_softc *sc, struct audio_info *ai, int need_mixerinfo,
@@ -7274,7 +7281,7 @@ audiogetinfo(struct audio_softc *sc, str
audio_track_t *rtrack;
int gain;
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock);
ri = &ai->record;
pi = &ai->play;
@@ -7367,7 +7374,7 @@ audiogetinfo(struct audio_softc *sc, str
}
if (need_mixerinfo) {
- KASSERT(sc->sc_exlock);
+ mutex_enter(sc->sc_lock);
pi->port = au_get_port(sc, &sc->sc_outports);
ri->port = au_get_port(sc, &sc->sc_inports);
@@ -7383,6 +7390,7 @@ audiogetinfo(struct audio_softc *sc, str
if (gain != -1)
ai->monitor_gain = gain;
}
+ mutex_exit(sc->sc_lock);
}
return 0;
@@ -7521,7 +7529,9 @@ audio_sysctl_blk_ms(SYSCTLFN_ARGS)
node = *rnode;
sc = node.sysctl_data;
- mutex_enter(sc->sc_lock);
+ error = audio_exlock_enter(sc);
+ if (error)
+ return error;
old_blk_ms = sc->sc_blk_ms;
t = old_blk_ms;
@@ -7568,7 +7578,7 @@ audio_sysctl_blk_ms(SYSCTLFN_ARGS)
}
error = 0;
abort:
- mutex_exit(sc->sc_lock);
+ audio_exlock_exit(sc);
return error;
}
@@ -7586,7 +7596,9 @@ audio_sysctl_multiuser(SYSCTLFN_ARGS)
node = *rnode;
sc = node.sysctl_data;
- mutex_enter(sc->sc_lock);
+ error = audio_exlock_enter(sc);
+ if (error)
+ return error;
t = sc->sc_multiuser;
node.sysctl_data = &t;
@@ -7597,7 +7609,7 @@ audio_sysctl_multiuser(SYSCTLFN_ARGS)
sc->sc_multiuser = t;
error = 0;
abort:
- mutex_exit(sc->sc_lock);
+ audio_exlock_exit(sc);
return error;
}
@@ -7677,7 +7689,7 @@ audio_suspend(device_t dv, const pmf_qua
struct audio_softc *sc = device_private(dv);
int error;
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_mutex_enter(sc);
if (error)
return error;
audio_mixer_capture(sc);
@@ -7695,7 +7707,7 @@ audio_suspend(device_t dv, const pmf_qua
#ifdef AUDIO_PM_IDLE
callout_halt(&sc->sc_idle_counter, sc->sc_lock);
#endif
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
return true;
}
@@ -7707,7 +7719,7 @@ audio_resume(device_t dv, const pmf_qual
struct audio_info ai;
int error;
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_mutex_enter(sc);
if (error)
return error;
@@ -7721,7 +7733,7 @@ audio_resume(device_t dv, const pmf_qual
if (sc->sc_rbusy)
audio_rmixer_start(sc);
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
return true;
}
@@ -7822,6 +7834,10 @@ audio_diagnostic_ring(const char *where,
/*
* Mixer driver
*/
+
+/*
+ * Must be called without sc_lock held.
+ */
int
mixer_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
struct lwp *l)
@@ -7830,8 +7846,6 @@ mixer_open(dev_t dev, struct audio_softc
audio_file_t *af;
int error, fd;
- KASSERT(mutex_owned(sc->sc_lock));
-
TRACE(1, "flags=0x%x", flags);
error = fd_allocfile(&fp, &fd);
@@ -7849,23 +7863,60 @@ mixer_open(dev_t dev, struct audio_softc
}
/*
+ * Add a process to those to be signalled on mixer activity.
+ * If the process has already been added, do nothing.
+ * Must be called with sc_exlock held and without sc_lock held.
+ */
+static void
+mixer_async_add(struct audio_softc *sc, pid_t pid)
+{
+ int i;
+
+ KASSERT(sc->sc_exlock);
+
+ /* If already exists, returns without doing anything. */
+ for (i = 0; i < sc->sc_am_used; i++) {
+ if (sc->sc_am[i] == pid)
+ return;
+ }
+
+ /* Extend array if necessary. */
+ if (sc->sc_am_used >= sc->sc_am_capacity) {
+ sc->sc_am_capacity += AM_CAPACITY;
+ sc->sc_am = kern_realloc(sc->sc_am,
+ sc->sc_am_capacity * sizeof(pid_t), M_WAITOK);
+ TRACE(2, "realloc am_capacity=%d", sc->sc_am_capacity);
+ }
+
+ TRACE(2, "am[%d]=%d", sc->sc_am_used, (int)pid);
+ sc->sc_am[sc->sc_am_used++] = pid;
+}
+
+/*
* Remove a process from those to be signalled on mixer activity.
- * Must be called with sc_lock held.
+ * If the process has not been added, do nothing.
+ * Must be called with sc_exlock held and without sc_lock held.
*/
static void
-mixer_remove(struct audio_softc *sc)
+mixer_async_remove(struct audio_softc *sc, pid_t pid)
{
- struct mixer_asyncs **pm, *m;
- pid_t pid;
+ int i;
- KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_exlock);
- pid = curproc->p_pid;
- for (pm = &sc->sc_async_mixer; *pm; pm = &(*pm)->next) {
- if ((*pm)->pid == pid) {
- m = *pm;
- *pm = m->next;
- kmem_free(m, sizeof(*m));
+ for (i = 0; i < sc->sc_am_used; i++) {
+ if (sc->sc_am[i] == pid) {
+ sc->sc_am[i] = sc->sc_am[--sc->sc_am_used];
+ TRACE(2, "am[%d](%d) removed, used=%d",
+ i, (int)pid, sc->sc_am_used);
+
+ /* Empty array if no longer necessary. */
+ if (sc->sc_am_used == 0) {
+ kern_free(sc->sc_am);
+ sc->sc_am = NULL;
+ sc->sc_am_capacity = 0;
+ TRACE(2, "released");
+ }
return;
}
}
@@ -7873,17 +7924,20 @@ mixer_remove(struct audio_softc *sc)
/*
* Signal all processes waiting for the mixer.
- * Must be called with sc_lock held.
+ * Must be called with sc_exlock held.
*/
static void
mixer_signal(struct audio_softc *sc)
{
- struct mixer_asyncs *m;
proc_t *p;
+ int i;
- for (m = sc->sc_async_mixer; m; m = m->next) {
+ KASSERT(sc->sc_exlock);
+
+ for (i = 0; i < sc->sc_am_used; i++) {
mutex_enter(proc_lock);
- if ((p = proc_find(m->pid)) != NULL)
+ p = proc_find(sc->sc_am[i]);
+ if (p)
psignal(p, SIGIO);
mutex_exit(proc_lock);
}
@@ -7895,11 +7949,14 @@ mixer_signal(struct audio_softc *sc)
int
mixer_close(struct audio_softc *sc, audio_file_t *file)
{
+ int error;
- mutex_enter(sc->sc_lock);
+ error = audio_exlock_enter(sc);
+ if (error)
+ return error;
TRACE(1, "");
- mixer_remove(sc);
- mutex_exit(sc->sc_lock);
+ mixer_async_remove(sc, curproc->p_pid);
+ audio_exlock_exit(sc);
return 0;
}
@@ -7911,7 +7968,6 @@ int
mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
struct lwp *l)
{
- struct mixer_asyncs *ma;
mixer_devinfo_t *mi;
mixer_ctrl_t *mc;
int error;
@@ -7929,29 +7985,22 @@ mixer_ioctl(struct audio_softc *sc, u_lo
switch (cmd) {
case FIOASYNC:
+ error = audio_exlock_enter(sc);
+ if (error)
+ break;
if (*(int *)addr) {
- ma = kmem_alloc(sizeof(struct mixer_asyncs), KM_SLEEP);
+ mixer_async_add(sc, curproc->p_pid);
} else {
- ma = NULL;
+ mixer_async_remove(sc, curproc->p_pid);
}
- mutex_enter(sc->sc_lock);
- mixer_remove(sc); /* remove old entry */
- if (ma != NULL) {
- ma->next = sc->sc_async_mixer;
- ma->pid = curproc->p_pid;
- sc->sc_async_mixer = ma;
- }
- mutex_exit(sc->sc_lock);
- error = 0;
+ audio_exlock_exit(sc);
break;
case AUDIO_GETDEV:
TRACE(2, "AUDIO_GETDEV");
- error = audio_enter_exclusive(sc);
- if (error)
- break;
+ mutex_enter(sc->sc_lock);
error = sc->hw_if->getdev(sc->hw_hdl, (audio_device_t *)addr);
- audio_exit_exclusive(sc);
+ mutex_exit(sc->sc_lock);
break;
case AUDIO_MIXER_DEVINFO:
@@ -7968,7 +8017,7 @@ mixer_ioctl(struct audio_softc *sc, u_lo
TRACE(2, "AUDIO_MIXER_READ");
mc = (mixer_ctrl_t *)addr;
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_mutex_enter(sc);
if (error)
break;
if (device_is_active(sc->hw_dev))
@@ -7981,39 +8030,38 @@ mixer_ioctl(struct audio_softc *sc, u_lo
sizeof(mixer_ctrl_t));
error = 0;
}
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
break;
case AUDIO_MIXER_WRITE:
TRACE(2, "AUDIO_MIXER_WRITE");
- error = audio_enter_exclusive(sc);
+ error = audio_exlock_mutex_enter(sc);
if (error)
break;
error = audio_set_port(sc, (mixer_ctrl_t *)addr);
if (error) {
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
break;
}
if (sc->hw_if->commit_settings) {
error = sc->hw_if->commit_settings(sc->hw_hdl);
if (error) {
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
break;
}
}
+ mutex_exit(sc->sc_lock);
mixer_signal(sc);
- audio_exit_exclusive(sc);
+ audio_exlock_exit(sc);
break;
default:
if (sc->hw_if->dev_ioctl) {
- error = audio_enter_exclusive(sc);
- if (error)
- break;
+ mutex_enter(sc->sc_lock);
error = sc->hw_if->dev_ioctl(sc->hw_hdl,
cmd, addr, flag, l);
- audio_exit_exclusive(sc);
+ mutex_exit(sc->sc_lock);
} else
error = EINVAL;
break;
@@ -8534,7 +8582,7 @@ audio_volume_down(device_t dv)
u_int gain;
u_char balance;
- if (audio_enter_exclusive(sc) != 0)
+ if (audio_exlock_mutex_enter(sc) != 0)
return;
if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {
mi.index = sc->sc_outports.master;
@@ -8547,7 +8595,7 @@ audio_volume_down(device_t dv)
au_set_gain(sc, &sc->sc_outports, newgain, balance);
}
}
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
}
static void
@@ -8558,7 +8606,7 @@ audio_volume_up(device_t dv)
u_int gain, newgain;
u_char balance;
- if (audio_enter_exclusive(sc) != 0)
+ if (audio_exlock_mutex_enter(sc) != 0)
return;
if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {
mi.index = sc->sc_outports.master;
@@ -8571,7 +8619,7 @@ audio_volume_up(device_t dv)
au_set_gain(sc, &sc->sc_outports, newgain, balance);
}
}
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
}
static void
@@ -8581,7 +8629,7 @@ audio_volume_toggle(device_t dv)
u_int gain, newgain;
u_char balance;
- if (audio_enter_exclusive(sc) != 0)
+ if (audio_exlock_mutex_enter(sc) != 0)
return;
au_get_gain(sc, &sc->sc_outports, &gain, &balance);
if (gain != 0) {
@@ -8590,9 +8638,12 @@ audio_volume_toggle(device_t dv)
} else
newgain = sc->sc_lastgain;
au_set_gain(sc, &sc->sc_outports, newgain, balance);
- audio_exit_exclusive(sc);
+ audio_exlock_mutex_exit(sc);
}
+/*
+ * Must be called with sc_lock held.
+ */
static int
audio_query_devinfo(struct audio_softc *sc, mixer_devinfo_t *di)
{
Index: src/sys/dev/audio/audiovar.h
diff -u src/sys/dev/audio/audiovar.h:1.4.2.2 src/sys/dev/audio/audiovar.h:1.4.2.3
--- src/sys/dev/audio/audiovar.h:1.4.2.2 Sat Mar 21 15:47:01 2020
+++ src/sys/dev/audio/audiovar.h Thu Apr 30 16:05:18 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: audiovar.h,v 1.4.2.2 2020/03/21 15:47:01 martin Exp $ */
+/* $NetBSD: audiovar.h,v 1.4.2.3 2020/04/30 16:05:18 martin Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -158,34 +158,37 @@ struct audio_softc {
/*
* Blocksize in msec.
- * Must be protected by sc_lock.
+ * Must be protected by sc_exlock.
*/
int sc_blk_ms;
/*
* Track mixer for playback and recording.
* If null, the mixer is disabled.
+ * Must be protected by sc_exlock.
*/
audio_trackmixer_t *sc_pmixer;
audio_trackmixer_t *sc_rmixer;
/*
* Opening track counter.
- * Must be protected by sc_lock.
+ * Must be protected by sc_lock && sc_exlock for modifying.
+ * Must be protected by sc_lock || sc_exlock for reference.
*/
int sc_popens;
int sc_ropens;
/*
* true if the track mixer is running.
- * Must be protected by sc_lock.
+ * Must be protected by sc_exlock && sc_intr_lock for modifying.
+ * Must be protected by sc_exlock || sc_intr_lock for reference.
*/
bool sc_pbusy;
bool sc_rbusy;
/*
* These four are the parameters sustained with /dev/sound.
- * Must be protected by sc_lock.
+ * Must be protected by sc_exlock.
*/
audio_format2_t sc_sound_pparams;
audio_format2_t sc_sound_rparams;
@@ -204,13 +207,15 @@ struct audio_softc {
struct selinfo sc_rsel;
/*
- * processes who want mixer SIGIO.
- * Must be protected by sc_lock.
- */
- struct mixer_asyncs {
- struct mixer_asyncs *next;
- pid_t pid;
- } *sc_async_mixer;
+ * Processes who want mixer SIGIO.
+ * sc_am is an array of pids, or NULL if empty.
+ * sc_am_capacity is the number of allocated elements.
+ * sc_am_used is the number of elements actually used.
+ * Must be protected by sc_exlock.
+ */
+ pid_t *sc_am;
+ int sc_am_capacity;
+ int sc_am_used;
/*
* Thread lock and interrupt lock obtained by get_locks().
@@ -240,7 +245,7 @@ struct audio_softc {
/*
* If multiuser is false, other users who have different euid
* than the first user cannot open this device.
- * Must be protected by sc_lock.
+ * Must be protected by sc_exlock.
*/
bool sc_multiuser;
kauth_cred_t sc_cred;