aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.19/950-0378-staging-bcm2835-audio-Fix-mute-controls-volume-handl.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.19/950-0378-staging-bcm2835-audio-Fix-mute-controls-volume-handl.patch')
-rw-r--r--target/linux/brcm2708/patches-4.19/950-0378-staging-bcm2835-audio-Fix-mute-controls-volume-handl.patch273
1 files changed, 273 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.19/950-0378-staging-bcm2835-audio-Fix-mute-controls-volume-handl.patch b/target/linux/brcm2708/patches-4.19/950-0378-staging-bcm2835-audio-Fix-mute-controls-volume-handl.patch
new file mode 100644
index 0000000000..de29b17d21
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.19/950-0378-staging-bcm2835-audio-Fix-mute-controls-volume-handl.patch
@@ -0,0 +1,273 @@
+From 31e4f118a750f4ddb2aeaaf02c5f3630fb50a176 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 4 Sep 2018 17:58:34 +0200
+Subject: [PATCH] staging: bcm2835-audio: Fix mute controls, volume
+ handling cleanup
+
+commit 495e5a0d83d3902c741771f267a702ae19da8ab6 upstream.
+
+In the current code, the mute control is dealt in a special manner,
+modifying the current volume and saving the old volume, etc. This is
+inconsistent (e.g. change the volume while muted, then unmute), and
+way too complex.
+
+Also, the whole volume handling code has conversion between ALSA
+volume and raw volume values, which can lead to another
+inconsistency and complexity.
+
+This patch simplifies these points:
+- The ALSA volume value is saved in chip->volume
+- volume->mute saves the mute state
+- The mute state is evaluated only when the actual volume is passed to
+ the hardware, bcm2835_audio_set_ctls()
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 84 +++++++------------
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 6 +-
+ .../bcm2835-audio/bcm2835-vchiq.c | 32 ++-----
+ .../vc04_services/bcm2835-audio/bcm2835.h | 5 +-
+ 4 files changed, 45 insertions(+), 82 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -12,6 +12,21 @@
+ #define CTRL_VOL_MAX 400
+ #define CTRL_VOL_MIN -10239 /* originally -10240 */
+
++static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
++{
++ int i, err = 0;
++
++ /* change ctls for all substreams */
++ for (i = 0; i < MAX_SUBSTREAMS; i++) {
++ if (chip->alsa_stream[i]) {
++ err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
++ if (err < 0)
++ break;
++ }
++ }
++ return err;
++}
++
+ static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+ {
+@@ -34,29 +49,6 @@ static int snd_bcm2835_ctl_info(struct s
+ return 0;
+ }
+
+-/* toggles mute on or off depending on the value of nmute, and returns
+- * 1 if the mute value was changed, otherwise 0
+- */
+-static int toggle_mute(struct bcm2835_chip *chip, int nmute)
+-{
+- /* if settings are ok, just return 0 */
+- if (chip->mute == nmute)
+- return 0;
+-
+- /* if the sound is muted then we need to unmute */
+- if (chip->mute == CTRL_VOL_MUTE) {
+- chip->volume = chip->old_volume; /* copy the old volume back */
+- audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
+- } else /* otherwise we mute */ {
+- chip->old_volume = chip->volume;
+- chip->volume = 26214; /* set volume to minimum level AKA mute */
+- audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
+- }
+-
+- chip->mute = nmute;
+- return 1;
+-}
+-
+ static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -65,7 +57,7 @@ static int snd_bcm2835_ctl_get(struct sn
+ mutex_lock(&chip->audio_mutex);
+
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
+- ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
++ ucontrol->value.integer.value[0] = chip->volume;
+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
+ ucontrol->value.integer.value[0] = chip->mute;
+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
+@@ -79,38 +71,26 @@ static int snd_bcm2835_ctl_put(struct sn
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ int val, *valp;
+ int changed = 0;
+
+- mutex_lock(&chip->audio_mutex);
+-
+- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
+- audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
+- if (chip->mute == CTRL_VOL_MUTE) {
+- /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
+- changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
+- goto unlock;
+- }
+- if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
+- chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
+- changed = 1;
+- }
+-
+- } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
+- /* Now implemented */
+- audio_info(" Mute attempted\n");
+- changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
++ valp = &chip->volume;
++ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
++ valp = &chip->mute;
++ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
++ valp = &chip->dest;
++ else
++ return -EINVAL;
+
+- } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
+- if (ucontrol->value.integer.value[0] != chip->dest) {
+- chip->dest = ucontrol->value.integer.value[0];
+- changed = 1;
+- }
++ val = ucontrol->value.integer.value[0];
++ mutex_lock(&chip->audio_mutex);
++ if (val != *valp) {
++ *valp = val;
++ changed = 1;
++ if (bcm2835_audio_set_chip_ctls(chip))
++ dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
+ }
+-
+- if (changed && bcm2835_audio_set_ctls(chip))
+- dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
+-
+-unlock:
+ mutex_unlock(&chip->audio_mutex);
+ return changed;
+ }
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -280,7 +280,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ bcm2835_audio_setup(alsa_stream);
+
+ /* in preparation of the stream, set the controls (volume level) of the stream */
+- bcm2835_audio_set_ctls(alsa_stream->chip);
++ bcm2835_audio_set_ctls(alsa_stream);
+
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+@@ -441,7 +441,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+ strcpy(pcm->name, "bcm2835 ALSA");
+ chip->pcm = pcm;
+ chip->dest = AUDIO_DEST_AUTO;
+- chip->volume = alsa2chip(0);
++ chip->volume = 0;
+ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
+ /* set operators */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+@@ -498,7 +498,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
+ strcpy(pcm->name, name);
+ chip->pcm = pcm;
+ chip->dest = route;
+- chip->volume = alsa2chip(0);
++ chip->volume = 0;
+ chip->mute = CTRL_VOL_UNMUTE;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -460,11 +460,11 @@ free_wq:
+ return ret;
+ }
+
+-static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
+- struct bcm2835_chip *chip)
++int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
++ struct bcm2835_chip *chip = alsa_stream->chip;
+ int status;
+ int ret;
+
+@@ -478,7 +478,10 @@ static int bcm2835_audio_set_ctls_chan(s
+
+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
+ m.u.control.dest = chip->dest;
+- m.u.control.volume = chip->volume;
++ if (!chip->mute)
++ m.u.control.volume = CHIP_MIN_VOLUME;
++ else
++ m.u.control.volume = alsa2chip(chip->volume);
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+@@ -514,27 +517,6 @@ unlock:
+ return ret;
+ }
+
+-int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
+-{
+- int i;
+- int ret = 0;
+-
+- LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
+-
+- /* change ctls for all substreams */
+- for (i = 0; i < MAX_SUBSTREAMS; i++) {
+- if (!chip->alsa_stream[i])
+- continue;
+- if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
+- LOG_ERR("Couldn't set the controls for stream %d\n", i);
+- ret = -1;
+- } else {
+- LOG_DBG(" Controls set for stream %d\n", i);
+- }
+- }
+- return ret;
+-}
+-
+ int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int channels, unsigned int samplerate,
+ unsigned int bps)
+@@ -548,7 +530,7 @@ int bcm2835_audio_set_params(struct bcm2
+ channels, samplerate, bps);
+
+ /* resend ctls - alsa_stream may not have been open when first send */
+- ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
++ ret = bcm2835_audio_set_ctls(alsa_stream);
+ if (ret) {
+ LOG_ERR(" Alsa controls not supported\n");
+ return -EINVAL;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -74,6 +74,8 @@ enum {
+ // convert chip to alsa volume
+ #define chip2alsa(vol) -(((vol) * 100) >> 8)
+
++#define CHIP_MIN_VOLUME 26214 /* minimum level aka mute */
++
+ /* Some constants for values .. */
+ enum snd_bcm2835_route {
+ AUDIO_DEST_AUTO = 0,
+@@ -102,7 +104,6 @@ struct bcm2835_chip {
+ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
+
+ int volume;
+- int old_volume; /* stores the volume value whist muted */
+ int dest;
+ int mute;
+
+@@ -160,7 +161,7 @@ int bcm2835_audio_set_params(struct bcm2
+ int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
+-int bcm2835_audio_set_ctls(struct bcm2835_chip *chip);
++int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count,
+ void *src);