Module Name:    src
Committed By:   nat
Date:           Tue Nov  7 01:13:19 UTC 2017

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

Log Message:
A sysctl is now available to disable the in kernel mixer.
        sysctl -w hw.hdafg0.usemixer=0

There currently is a problem draining the last block with the mixer
disabled.  I will fix this in a follow up commit.

AFAIK there will be a problem wiht vs(4) on x68k with the mixer disabled
as the filters for mulaw, alaw and unsigned linear have been removed post
audio mixing changes.

Documentation for this sysctl variable will be made to audio.4 in a follow
up commit.

Ok christos@.


To generate a diff of this commit:
cvs rdiff -u -r1.429 -r1.430 src/sys/dev/audio.c
cvs rdiff -u -r1.66 -r1.67 src/sys/dev/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.c
diff -u src/sys/dev/audio.c:1.429 src/sys/dev/audio.c:1.430
--- src/sys/dev/audio.c:1.429	Sat Nov  4 01:50:48 2017
+++ src/sys/dev/audio.c	Tue Nov  7 01:13:19 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: audio.c,v 1.429 2017/11/04 01:50:48 nat Exp $	*/
+/*	$NetBSD: audio.c,v 1.430 2017/11/07 01:13:19 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.429 2017/11/04 01:50:48 nat Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.430 2017/11/07 01:13:19 nat Exp $");
 
 #ifdef _KERNEL_OPT
 #include "audio.h"
@@ -320,6 +320,7 @@ static int audio_sysctl_frequency(SYSCTL
 static int audio_sysctl_precision(SYSCTLFN_PROTO);
 static int audio_sysctl_channels(SYSCTLFN_PROTO);
 static int audio_sysctl_latency(SYSCTLFN_PROTO);
+static int audio_sysctl_usemixer(SYSCTLFN_PROTO);
 
 static int	audiomatch(device_t, cfdata_t, void *);
 static void	audioattach(device_t, device_t, void *);
@@ -608,6 +609,7 @@ audioattach(device_t parent, device_t se
 
 	sc->sc_lastgain = 128;
 	sc->sc_multiuser = false;
+	sc->sc_usemixer = true;
 
 	error = vchan_autoconfig(sc);
 	if (error != 0) {
@@ -814,6 +816,15 @@ audioattach(device_t parent, device_t se
 			&sc->sc_multiuser, 0,
 			CTL_HW, node->sysctl_num,
 			CTL_CREATE, CTL_EOL);
+
+		sysctl_createv(&sc->sc_log, 0, NULL, NULL,
+			CTLFLAG_READWRITE,
+			CTLTYPE_BOOL, "usemixer",
+			SYSCTL_DESCR("allow in-kernel mixing"),
+			audio_sysctl_usemixer, 0,
+			(void *)sc, 0,
+			CTL_HW, node->sysctl_num,
+			CTL_CREATE, CTL_EOL);
 	}
 
 	selinit(&sc->sc_rsel);
@@ -1594,6 +1605,9 @@ audio_waitio(struct audio_softc *sc, kco
 	/* Wait for pending I/O to complete. */
 	error = cv_wait_sig(chan, sc->sc_lock);
 
+	if (!sc->sc_usemixer)
+		return error;
+
 	found = false;
 	SIMPLEQ_FOREACH(vchan, &sc->sc_audiochan, entries) {
 		if (vchan->vc == vc) {
@@ -2153,7 +2167,7 @@ audio_open(dev_t dev, struct audio_softc
 
 	KASSERT(mutex_owned(sc->sc_lock));
 
-	if (sc->sc_ready == false)
+	if (sc->sc_usemixer && !sc->sc_ready)
 		return ENXIO;
 
 	hw = sc->hw_if;
@@ -2166,36 +2180,50 @@ audio_open(dev_t dev, struct audio_softc
 		n = chan->chan + 1;
 
 	chan = kmem_zalloc(sizeof(struct audio_chan), KM_SLEEP);
-	vc = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
+	if (sc->sc_usemixer)
+		vc = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
+	else
+		vc = sc->sc_hwvc;
 	chan->vc = vc;
 
-	vc->sc_open = 0;
-	vc->sc_mode = 0;
-	vc->sc_sil_count = 0;
-	vc->sc_nrfilters = 0;
-	memset(vc->sc_rfilters, 0,
-	    sizeof(vc->sc_rfilters));
-	vc->sc_rbus = false;
-	vc->sc_npfilters = 0;
-	memset(vc->sc_pfilters, 0,
-	    sizeof(vc->sc_pfilters));
-	vc->sc_draining = false;
-	vc->sc_pbus = false;
-	vc->sc_lastinfovalid = false;
-	vc->sc_swvol = 255;
-	vc->sc_recswvol = 255;
+	if (sc->sc_usemixer) {
+		vc->sc_open = 0;
+		vc->sc_mode = 0;
+		vc->sc_sil_count = 0;
+		vc->sc_nrfilters = 0;
+		memset(vc->sc_rfilters, 0,
+		    sizeof(vc->sc_rfilters));
+		vc->sc_rbus = false;
+		vc->sc_npfilters = 0;
+		memset(vc->sc_pfilters, 0,
+		    sizeof(vc->sc_pfilters));
+		vc->sc_draining = false;
+		vc->sc_pbus = false;
+		vc->sc_lastinfovalid = false;
+		vc->sc_swvol = 255;
+		vc->sc_recswvol = 255;
+	} else {
+		if (sc->sc_opens > 0 || sc->sc_recopens > 0 ) {
+			kmem_free(chan, sizeof(struct audio_chan));
+			return EBUSY;
+		}
+	}
 
 	DPRINTF(("audio_open: flags=0x%x sc=%p hdl=%p\n",
 		 flags, sc, sc->hw_hdl));
 
-	error = audio_alloc_ring(sc, &vc->sc_mpr, AUMODE_PLAY, AU_RING_SIZE);
-	if (error)
-		goto bad;
-	error = audio_alloc_ring(sc, &vc->sc_mrr, AUMODE_RECORD, AU_RING_SIZE);
-	if (error)
-		goto bad;
+	if (sc->sc_usemixer) {
+		error = audio_alloc_ring(sc, &vc->sc_mpr, AUMODE_PLAY,
+		    AU_RING_SIZE);
+		if (error)
+			goto bad;
+		error = audio_alloc_ring(sc, &vc->sc_mrr, AUMODE_RECORD,
+		    AU_RING_SIZE);
+		if (error)
+			goto bad;
+	}
 
-	if (sc->sc_opens + sc->sc_recopens == 0) {
+	if (!sc->sc_usemixer || sc->sc_opens + sc->sc_recopens == 0) {
 		sc->sc_credentials = kauth_cred_get();
 		kauth_cred_hold(sc->sc_credentials);
 		if (hw->open != NULL) {
@@ -2290,7 +2318,8 @@ audio_open(dev_t dev, struct audio_softc
 	chan->dev = dev;
 	chan->chan = n;
 	chan->deschan = n;
-	SIMPLEQ_INSERT_TAIL(&sc->sc_audiochan, chan, entries);
+	if (sc->sc_usemixer)
+		SIMPLEQ_INSERT_TAIL(&sc->sc_audiochan, chan, entries);
 
 	error = fd_clone(fp, fd, flags, &audio_fileops, chan);
 	KASSERT(error == EMOVEFD);
@@ -2304,10 +2333,14 @@ bad:
 	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);
-	audio_free_ring(sc, &vc->sc_mrr);
-	mutex_enter(sc->sc_lock);
-	kmem_free(vc, sizeof(struct virtual_channel));
+	if (sc->sc_usemixer) {
+		audio_free_ring(sc, &vc->sc_mpr);
+		audio_free_ring(sc, &vc->sc_mrr);
+		mutex_enter(sc->sc_lock);
+		kmem_free(vc, sizeof(struct virtual_channel));
+	} else
+		mutex_enter(sc->sc_lock);
+
 	kmem_free(chan, sizeof(struct audio_chan));
 	return error;
 }
@@ -2518,13 +2551,15 @@ audio_close(struct audio_softc *sc, int 
 		sc->sc_recopens--;
 	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);
-	audio_free_ring(sc, &vc->sc_mpr);
-	audio_free_ring(sc, &vc->sc_mrr);
-	mutex_enter(sc->sc_lock);
-	kmem_free(vc, sizeof(struct virtual_channel));
+	if (sc->sc_usemixer) {
+		shrink_mixer_states(sc, 2);
+		SIMPLEQ_REMOVE(&sc->sc_audiochan, chan, audio_chan, entries);
+		mutex_exit(sc->sc_lock);
+		audio_free_ring(sc, &vc->sc_mpr);
+		audio_free_ring(sc, &vc->sc_mrr);
+		mutex_enter(sc->sc_lock);
+		kmem_free(vc, sizeof(struct virtual_channel));
+	}
 
 	return 0;
 }
@@ -3038,12 +3073,15 @@ audio_ioctl(dev_t dev, struct audio_soft
 
 	KASSERT(mutex_owned(sc->sc_lock));
 
-	SIMPLEQ_FOREACH(pchan, &sc->sc_audiochan, entries) {
-		if (pchan->chan == chan->deschan)
-			break;
-	}
-	if (pchan == NULL)
-		return ENXIO;
+	if (sc->sc_usemixer) {
+		SIMPLEQ_FOREACH(pchan, &sc->sc_audiochan, entries) {
+			if (pchan->chan == chan->deschan)
+				break;
+		}
+		if (pchan == NULL)
+			return ENXIO;
+	} else
+		pchan = chan;
 
 	vc = pchan->vc;
 
@@ -3515,14 +3553,15 @@ audiostartr(struct audio_softc *sc, stru
 
 	if (!audio_can_capture(sc))
 		return EINVAL;
-	if (vc == sc->sc_hwvc)
+	if (vc == sc->sc_hwvc && sc->sc_usemixer)
 		return 0;
 
 	error = 0;
 	if (sc->sc_rec_started == false) {
 		mutex_enter(sc->sc_intr_lock);
 		error = mix_read(sc);
-		cv_broadcast(&sc->sc_rcondvar);
+		if (sc->sc_usemixer)
+			cv_broadcast(&sc->sc_rcondvar);
 		mutex_exit(sc->sc_intr_lock);
 	}
 	vc->sc_rbus = true;
@@ -3545,7 +3584,7 @@ audiostartp(struct audio_softc *sc, stru
 
 	if (!audio_can_playback(sc))
 		return EINVAL;
-	if (vc == sc->sc_hwvc)
+	if (vc == sc->sc_hwvc && sc->sc_usemixer)
 		return 0;
 
 	if (!vc->sc_mpr.mmapped && used < sc->sc_mixring.sc_mpr.blksize) {
@@ -3556,9 +3595,11 @@ audiostartp(struct audio_softc *sc, stru
 	
 	vc->sc_pbus = true;
 	if (sc->sc_trigger_started == false) {
-		audio_mix(sc);
-		audio_mix(sc);
-		audio_mix(sc);
+		if (sc->sc_usemixer) {
+			audio_mix(sc);
+			audio_mix(sc);
+			audio_mix(sc);
+		}
 		mutex_enter(sc->sc_intr_lock);
 		error = mix_write(sc);
 		if (error)
@@ -3568,7 +3609,8 @@ audiostartp(struct audio_softc *sc, stru
 		    audio_stream_add_outp(&vc->sc_mpr.s,
 		      vc->sc_mpr.s.outp, vc->sc_mpr.blksize);
 		error = mix_write(sc);
-		cv_broadcast(&sc->sc_condvar);
+		if (sc->sc_usemixer)
+			cv_broadcast(&sc->sc_condvar);
 done:
 		mutex_exit(sc->sc_intr_lock);
 	}
@@ -3690,8 +3732,8 @@ audio_pint(void *v)
 	if (sc->sc_dying == true || sc->sc_trigger_started == false)
 		return;
 
-	if (vc->sc_draining == true && sc->sc_mixring.sc_mpr.drops !=
-						sc->sc_last_drops) {
+	if (vc->sc_draining && (!sc->sc_usemixer ||
+	    (sc->sc_mixring.sc_mpr.drops != sc->sc_last_drops))) {
 		vc->sc_mpr.drops += blksize;
 		cv_broadcast(&sc->sc_wchan);
 	}
@@ -3719,7 +3761,10 @@ audio_pint(void *v)
 
 	mix_write(sc);
 
-	cv_broadcast(&sc->sc_condvar);
+	if (sc->sc_usemixer)
+		cv_broadcast(&sc->sc_condvar);
+	else
+		cv_broadcast(&sc->sc_wchan);
 }
 
 void
@@ -3744,7 +3789,7 @@ audio_mix(void *v)
 	if (sc->sc_dying == true)
 		return;
 
-	blksize = sc->sc_mixring.sc_mpr.blksize;
+	blksize = sc->sc_hwvc->sc_mpr.blksize;
 	SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
 		vc = chan->vc;
 
@@ -3937,7 +3982,10 @@ audio_rint(void *v)
 		sc->sc_mixring.sc_mrr.s.outp, blksize);
 	mix_read(sc);
 
-	cv_broadcast(&sc->sc_rcondvar);
+	if (sc->sc_usemixer)
+		cv_broadcast(&sc->sc_rcondvar);
+	else
+		cv_broadcast(&sc->sc_rchan);
 }
 
 void
@@ -5502,11 +5550,13 @@ mix_write(void *arg)
 	vc = sc->sc_hwvc;
 	error = 0;
 
-	if (audio_stream_get_used(vc->sc_pustream) <=
-				sc->sc_mixring.sc_mpr.blksize) {
+	if (sc->sc_usemixer &&
+	    audio_stream_get_used(vc->sc_pustream) <=
+				vc->sc_mpr.blksize) {
 		tocopy = vc->sc_pustream->inp;
 		orig = sc->sc_mixring.sc_mpr.s.outp;
-		used = sc->sc_mixring.sc_mpr.blksize;
+		used = vc->sc_mpr.blksize;
+
 		while (used > 0) {
 			cc = used;
 			cc1 = vc->sc_pustream->end - tocopy;
@@ -5528,12 +5578,12 @@ mix_write(void *arg)
 		}
 
 		vc->sc_pustream->inp = audio_stream_add_inp(vc->sc_pustream,
-		    vc->sc_pustream->inp, sc->sc_mixring.sc_mpr.blksize);
+		    vc->sc_pustream->inp, vc->sc_mpr.blksize);
 
 		sc->sc_mixring.sc_mpr.s.outp =
 		    audio_stream_add_outp(&sc->sc_mixring.sc_mpr.s,
 		    	sc->sc_mixring.sc_mpr.s.outp,
-			sc->sc_mixring.sc_mpr.blksize);
+			vc->sc_mpr.blksize);
 	}
 
 	if (vc->sc_npfilters > 0) {
@@ -5807,7 +5857,7 @@ audio_set_params(struct audio_softc *sc,
 
 	if (vc == sc->sc_hwvc) {
 		sc->sc_ready = true;
-		if (sc->sc_vchan_params.precision == 8)
+		if (sc->sc_usemixer && sc->sc_vchan_params.precision == 8)
 			play->encoding = rec->encoding = AUDIO_ENCODING_SLINEAR;
 		error = sc->hw_if->set_params(sc->hw_hdl, setmode, usemode,
  		    play, rec, pfil, rfil);
@@ -5851,7 +5901,8 @@ audio_play_thread(void *v)
 			kthread_exit(0);
 		}
 
-		while (audio_stream_get_used(&sc->sc_mixring.sc_mpr.s) <
+		while (sc->sc_trigger_started && sc->sc_usemixer &&
+		    audio_stream_get_used(&sc->sc_mixring.sc_mpr.s) <
 						sc->sc_mixring.sc_mpr.blksize) {
 			mutex_exit(sc->sc_intr_lock);
 			mutex_enter(sc->sc_lock);
@@ -5983,6 +6034,54 @@ audio_sysctl_precision(SYSCTLFN_ARGS)
 	return error;
 }
 
+/* sysctl helper to enable/disable channel mixing */
+static int
+audio_sysctl_usemixer(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct audio_softc *sc;
+	bool t;
+	int error;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+
+	t = sc->sc_usemixer;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	mutex_enter(sc->sc_lock);
+
+	/* This may not change when a virtual channel is open */
+	if (sc->sc_opens) {
+		mutex_exit(sc->sc_lock);
+		return EBUSY;
+	}
+
+	sc->sc_usemixer = t;
+	audio_destroy_pfilters(sc->sc_hwvc);
+	audio_destroy_rfilters(sc->sc_hwvc);
+	if (t) {
+		error = audio_set_vchan_defaults(sc,
+		    AUMODE_PLAY | AUMODE_PLAY_ALL | AUMODE_RECORD);
+		if (error)
+			aprint_error_dev(sc->sc_dev, "Error setting precision, "
+					 "please check hardware capabilities\n");
+	}
+
+	if (sc->sc_usemixer) {
+		if (error == 0)
+			audio_calc_latency(sc);
+	} else
+		sc->sc_latency = audio_blk_ms * PREFILL_BLOCKS;
+		
+	mutex_exit(sc->sc_lock);
+
+	return error;
+}
+
 /* sysctl helper to set common audio channels */
 static int
 audio_sysctl_channels(SYSCTLFN_ARGS)

Index: src/sys/dev/audiovar.h
diff -u src/sys/dev/audiovar.h:1.66 src/sys/dev/audiovar.h:1.67
--- src/sys/dev/audiovar.h:1.66	Thu Oct 26 22:38:27 2017
+++ src/sys/dev/audiovar.h	Tue Nov  7 01:13:19 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: audiovar.h,v 1.66 2017/10/26 22:38:27 nat Exp $	*/
+/*	$NetBSD: audiovar.h,v 1.67 2017/11/07 01:13:19 nat Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -204,6 +204,7 @@ struct audio_softc {
 	bool		sc_trigger_started;
 	bool		sc_rec_started;
 	bool		sc_writeme;
+	bool		sc_usemixer;
 	bool		sc_ready;	/* audio hw configured properly */
 	unsigned int	sc_latency;
 	int		sc_opens;

Reply via email to