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;