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;