Module Name:    src
Committed By:   nat
Date:           Sun Oct  1 21:49:20 UTC 2017

Modified Files:
        src/sys/dev: audio.c

Log Message:
Ensure proper use of sc_opens (play back) and sc_recopens (recording).
Fix logic for /dev/sound so audiosetinfo is only called once.

These changes are to ensure that init_output/input is only called once for
the respective function play back or recording.  For multiple recording or
plack back streams init_input/output is only called once fot the first
play/rec stream.

This addresses PR kern/52580, PR kern/52581 and PR kern/52582 analyzed and
reported by isaki@.


To generate a diff of this commit:
cvs rdiff -u -r1.409 -r1.410 src/sys/dev/audio.c

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.c
diff -u src/sys/dev/audio.c:1.409 src/sys/dev/audio.c:1.410
--- src/sys/dev/audio.c:1.409	Sat Sep 30 05:37:55 2017
+++ src/sys/dev/audio.c	Sun Oct  1 21:49:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: audio.c,v 1.409 2017/09/30 05:37:55 isaki Exp $	*/
+/*	$NetBSD: audio.c,v 1.410 2017/10/01 21:49:20 nat Exp $	*/
 
 /*-
  * Copyright (c) 2016 Nathanial Sloss <nathanialsl...@yahoo.com.au>
@@ -148,7 +148,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.409 2017/09/30 05:37:55 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.410 2017/10/01 21:49:20 nat Exp $");
 
 #ifdef _KERNEL_OPT
 #include "audio.h"
@@ -2027,7 +2027,7 @@ audio_initbufs(struct audio_softc *sc, s
 		((vc->sc_open & AUOPEN_READ) || vc == sc->sc_hwvc)) {
 		audio_init_ringbuffer(sc, &vc->sc_mrr,
 		    AUMODE_RECORD);
-		if (sc->sc_opens == 0 && (vc->sc_mode & AUMODE_RECORD)) {
+		if (sc->sc_recopens == 0 && (vc->sc_open & AUOPEN_READ)) {
 			if (hw->init_input) {
 				error = hw->init_input(sc->hw_hdl,
 				    vc->sc_mrr.s.start,
@@ -2043,7 +2043,7 @@ audio_initbufs(struct audio_softc *sc, s
 		audio_init_ringbuffer(sc, &vc->sc_mpr,
 		    AUMODE_PLAY);
 		vc->sc_sil_count = 0;
-		if (sc->sc_opens == 0 && (vc->sc_mode & AUMODE_PLAY)) {
+		if (sc->sc_opens == 0 && (vc->sc_open & AUOPEN_WRITE)) {
 			if (hw->init_output) {
 				error = hw->init_output(sc->hw_hdl,
 				    vc->sc_mpr.s.start,
@@ -2157,7 +2157,7 @@ audio_open(dev_t dev, struct audio_softc
 	if (error)
 		goto bad;
 
-	if (sc->sc_opens == 0) {
+	if (sc->sc_opens + sc->sc_recopens == 0) {
 		sc->sc_credentials = kauth_cred_get();
 		kauth_cred_hold(sc->sc_credentials);
 		if (hw->open != NULL) {
@@ -2216,13 +2216,13 @@ audio_open(dev_t dev, struct audio_softc
 	 * The /dev/audio is always (re)set to 8-bit MU-Law mono
 	 * For the other devices, you get what they were last set to.
 	 */
-	error = audio_set_defaults(sc, mode, vc);
-	if (!error && ISDEVSOUND(dev) && sc->sc_aivalid == true) {
+	if (ISDEVSOUND(dev) && sc->sc_aivalid == true) {
 		sc->sc_ai.mode = mode;
 		sc->sc_ai.play.port = ~0;
 		sc->sc_ai.record.port = ~0;
 		error = audiosetinfo(sc, &sc->sc_ai, true, vc);
-	}
+	} else
+		error = audio_set_defaults(sc, mode, vc);
 	if (error)
 		goto bad;
 
@@ -2250,7 +2250,8 @@ audio_open(dev_t dev, struct audio_softc
 	grow_mixer_states(sc, 2);
 	if (flags & FREAD)
 		sc->sc_recopens++;
-	sc->sc_opens++;
+	if (flags & FWRITE)
+		sc->sc_opens++;
 	chan->dev = dev;
 	chan->chan = n;
 	chan->deschan = n;
@@ -2265,7 +2266,7 @@ audio_open(dev_t dev, struct audio_softc
 bad:
 	audio_destroy_pfilters(vc);
 	audio_destroy_rfilters(vc);
-	if (hw->close != NULL && sc->sc_opens == 0)
+	if (hw->close != NULL && sc->sc_opens == 0 && sc->sc_recopens == 0)
 		hw->close(sc->hw_hdl);
 	mutex_exit(sc->sc_lock);
 	audio_free_ring(sc, &vc->sc_mpr);
@@ -2285,7 +2286,7 @@ audio_init_record(struct audio_softc *sc
 
 	KASSERT(mutex_owned(sc->sc_lock));
 	
-	if (sc->sc_opens != 0)
+	if (sc->sc_recopens != 0)
 		return;
 
 	mutex_enter(sc->sc_intr_lock);
@@ -2416,7 +2417,7 @@ audio_close(struct audio_softc *sc, int 
 
 	KASSERT(mutex_owned(sc->sc_lock));
 	
-	if (sc->sc_opens == 0)
+	if (sc->sc_opens == 0 && sc->sc_recopens == 0)
 		return ENXIO;
 
 	vc = chan->vc;
@@ -2450,7 +2451,7 @@ audio_close(struct audio_softc *sc, int 
 			audio_drain(sc, chan->vc);
 		vc->sc_pbus = false;
 	}
-	if (sc->sc_opens == 1) {
+	if ((flags & FWRITE) && (sc->sc_opens == 1)) {
 		if (vc->sc_mpr.mmapped == false)
 			audio_drain(sc, sc->sc_hwvc);
 		if (hw->drain)
@@ -2461,11 +2462,11 @@ audio_close(struct audio_softc *sc, int 
 	if ((flags & FREAD) && (sc->sc_recopens == 1))
 		sc->sc_rec_started = false;
 
-	if (sc->sc_opens == 1 && hw->close != NULL)
+	if (sc->sc_opens + sc->sc_recopens == 1 && hw->close != NULL)
 		hw->close(sc->hw_hdl);
 	mutex_exit(sc->sc_intr_lock);
 
-	if (sc->sc_opens == 1) {
+	if (sc->sc_opens + sc->sc_recopens == 1) {
 		sc->sc_async_audio = 0;
 		kauth_cred_free(sc->sc_credentials);
 	}
@@ -2479,7 +2480,8 @@ audio_close(struct audio_softc *sc, int 
 
 	if (flags & FREAD)
 		sc->sc_recopens--;
-	sc->sc_opens--;
+	if (flags & FWRITE)
+		sc->sc_opens--;
 	shrink_mixer_states(sc, 2);
 	SIMPLEQ_REMOVE(&sc->sc_audiochan, chan, audio_chan, entries);
 	mutex_exit(sc->sc_lock);
@@ -4710,7 +4712,7 @@ audiosetinfo(struct audio_softc *sc, str
 		}
 	}
 
-	if (hw->commit_settings && sc->sc_opens == 0) {
+	if (hw->commit_settings && sc->sc_opens + sc->sc_recopens == 0) {
 		error = hw->commit_settings(sc->hw_hdl);
 		if (error)
 			goto cleanup;
@@ -5830,7 +5832,7 @@ audio_sysctl_frequency(SYSCTLFN_ARGS)
 	mutex_enter(sc->sc_lock);
 
 	/* This may not change when a virtual channel is open */
-	if (sc->sc_opens) {
+	if (sc->sc_opens || sc->sc_recopens) {
 		mutex_exit(sc->sc_lock);
 		return EBUSY;
 	}
@@ -5871,7 +5873,7 @@ audio_sysctl_precision(SYSCTLFN_ARGS)
 	mutex_enter(sc->sc_lock);
 
 	/* This may not change when a virtual channel is open */
-	if (sc->sc_opens) {
+	if (sc->sc_opens || sc->sc_recopens) {
 		mutex_exit(sc->sc_lock);
 		return EBUSY;
 	}
@@ -5923,7 +5925,7 @@ audio_sysctl_channels(SYSCTLFN_ARGS)
 	mutex_enter(sc->sc_lock);
 
 	/* This may not change when a virtual channel is open */
-	if (sc->sc_opens) {
+	if (sc->sc_opens || sc->sc_recopens) {
 		mutex_exit(sc->sc_lock);
 		return EBUSY;
 	}

Reply via email to