diff options
author | Oswald Buddenhagen <oswald.buddenhagen@gmx.de> | 2023-05-16 11:36:10 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2023-05-17 17:04:34 +0200 |
commit | 35a60d1edff4dec9a31862a3515676cd0fafe4e4 (patch) | |
tree | 93ccdcddca6eac7f9cc602f075dc0a0756145e74 /sound/pci | |
parent | a61c695aee87ba9c9f6b2996f98e933e3c33a049 (diff) | |
download | linux-stable-35a60d1edff4dec9a31862a3515676cd0fafe4e4.tar.gz linux-stable-35a60d1edff4dec9a31862a3515676cd0fafe4e4.tar.bz2 linux-stable-35a60d1edff4dec9a31862a3515676cd0fafe4e4.zip |
ALSA: emu10k1: rewire {en,dis}abling interrupts for PCM playback
We now enable ints even before triggering, and disable them only after
stopping - otherwise there is a race condition we may plausibly run into
when we pause/resume near the end of the buffer.
Updating the epcm->running flag is moved the same way, as it affects the
*_pointer() functions, which are called by the interrupt handler.
Also, factor these out to own functions, for clarity.
For multi-channel, the extra voice is now triggered after all regular
voices - we wouldn't want to receive an int before all channels have
passed the period boundary.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Link: https://lore.kernel.org/r/20230516093612.3536451-5-oswald.buddenhagen@gmx.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/emu10k1/emupcm.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 2b6f5d2bbb3e..7b0ab4e02cfd 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -605,7 +605,9 @@ static void snd_emu10k1_playback_prepare_voice(struct snd_emu10k1 *emu, struct s snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | CVCF_CURRENTFILTER_MASK); } -static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice, int master, int extra) +static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + int master) { struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; @@ -624,24 +626,36 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); if (master || evoice->epcm->type == PLAYBACK_EFX) snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); - if (extra) - snd_emu10k1_voice_intr_enable(emu, voice); } -static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice) +static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice) { unsigned int voice; if (evoice == NULL) return; voice = evoice->number; - snd_emu10k1_voice_intr_disable(emu, voice); snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0); snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0); snd_emu10k1_ptr_write(emu, VTFT, voice, VTFT_FILTERTARGET_MASK); snd_emu10k1_ptr_write(emu, CVCF, voice, CVCF_CURRENTFILTER_MASK); } +static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm) +{ + epcm->running = 1; + snd_emu10k1_voice_intr_enable(emu, epcm->extra->number); +} + +static void snd_emu10k1_playback_set_stopped(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm) +{ + snd_emu10k1_voice_intr_disable(emu, epcm->extra->number); + epcm->running = 0; +} + static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, struct snd_emu10k1_pcm *epcm, struct snd_pcm_substream *substream, @@ -687,18 +701,18 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, mix); snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, mix); snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, NULL); - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0); - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0); - snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); - epcm->running = 1; + snd_emu10k1_playback_set_running(emu, epcm); + snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1); + snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0); + snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - epcm->running = 0; snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]); snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]); snd_emu10k1_playback_stop_voice(emu, epcm->extra); + snd_emu10k1_playback_set_stopped(emu, epcm); break; default: result = -EINVAL; @@ -836,20 +850,19 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, for (i = 1; i < NUM_EFX_PLAYBACK; i++) snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0, &emu->efx_pcm_mixer[i]); - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 0, 0); - snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); - for (i = 1; i < NUM_EFX_PLAYBACK; i++) - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0); - epcm->running = 1; + snd_emu10k1_playback_set_running(emu, epcm); + for (i = 0; i < NUM_EFX_PLAYBACK; i++) + snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0); + snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - epcm->running = 0; for (i = 0; i < NUM_EFX_PLAYBACK; i++) { snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]); } snd_emu10k1_playback_stop_voice(emu, epcm->extra); + snd_emu10k1_playback_set_stopped(emu, epcm); break; default: result = -EINVAL; |