Commit 23ba2861 authored by Srinivas Kandagatla's avatar Srinivas Kandagatla Committed by Mark Brown

ASoC: codecs: wcd934x: handle channel mappping list correctly

Currently each channel is added as list to dai channel list, however
there is danger of adding same channel to multiple dai channel list
which endups corrupting the other list where its already added.

This patch ensures that the channel is actually free before adding to
the dai channel list and also ensures that the channel is on the list
before deleting it.

This check was missing previously, and we did not hit this issue as
we were testing very simple usecases with sequence of amixer commands.

Fixes: a70d9245 ("ASoC: wcd934x: add capture dapm widgets")
Fixes: dd9eb19b ("ASoC: wcd934x: add playback dapm widgets")
Signed-off-by: default avatarSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20211130160507.22180-2-srinivas.kandagatla@linaro.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 4739d88a
......@@ -3326,6 +3326,31 @@ static int slim_rx_mux_get(struct snd_kcontrol *kc,
return 0;
}
static int slim_rx_mux_to_dai_id(int mux)
{
int aif_id;
switch (mux) {
case 1:
aif_id = AIF1_PB;
break;
case 2:
aif_id = AIF2_PB;
break;
case 3:
aif_id = AIF3_PB;
break;
case 4:
aif_id = AIF4_PB;
break;
default:
aif_id = -1;
break;
}
return aif_id;
}
static int slim_rx_mux_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
......@@ -3333,43 +3358,59 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
struct wcd934x_codec *wcd = dev_get_drvdata(w->dapm->dev);
struct soc_enum *e = (struct soc_enum *)kc->private_value;
struct snd_soc_dapm_update *update = NULL;
struct wcd934x_slim_ch *ch, *c;
u32 port_id = w->shift;
bool found = false;
int mux_idx;
int prev_mux_idx = wcd->rx_port_value[port_id];
int aif_id;
if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
return 0;
mux_idx = ucontrol->value.enumerated.item[0];
wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
if (mux_idx == prev_mux_idx)
return 0;
switch (wcd->rx_port_value[port_id]) {
switch(mux_idx) {
case 0:
list_del_init(&wcd->rx_chs[port_id].list);
break;
case 1:
list_add_tail(&wcd->rx_chs[port_id].list,
&wcd->dai[AIF1_PB].slim_ch_list);
break;
case 2:
list_add_tail(&wcd->rx_chs[port_id].list,
&wcd->dai[AIF2_PB].slim_ch_list);
break;
case 3:
list_add_tail(&wcd->rx_chs[port_id].list,
&wcd->dai[AIF3_PB].slim_ch_list);
aif_id = slim_rx_mux_to_dai_id(prev_mux_idx);
if (aif_id < 0)
return 0;
list_for_each_entry_safe(ch, c, &wcd->dai[aif_id].slim_ch_list, list) {
if (ch->port == port_id + WCD934X_RX_START) {
found = true;
list_del_init(&ch->list);
break;
}
}
if (!found)
return 0;
break;
case 4:
list_add_tail(&wcd->rx_chs[port_id].list,
&wcd->dai[AIF4_PB].slim_ch_list);
case 1 ... 4:
aif_id = slim_rx_mux_to_dai_id(mux_idx);
if (aif_id < 0)
return 0;
if (list_empty(&wcd->rx_chs[port_id].list)) {
list_add_tail(&wcd->rx_chs[port_id].list,
&wcd->dai[aif_id].slim_ch_list);
} else {
dev_err(wcd->dev ,"SLIM_RX%d PORT is busy\n", port_id);
return 0;
}
break;
default:
dev_err(wcd->dev, "Unknown AIF %d\n",
wcd->rx_port_value[port_id]);
dev_err(wcd->dev, "Unknown AIF %d\n", mux_idx);
goto err;
}
wcd->rx_port_value[port_id] = mux_idx;
snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id],
e, update);
return 0;
return 1;
err:
return -EINVAL;
}
......@@ -3815,6 +3856,7 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kc->private_value;
int enable = ucontrol->value.integer.value[0];
struct wcd934x_slim_ch *ch, *c;
int dai_id = widget->shift;
int port_id = mixer->shift;
......@@ -3822,17 +3864,32 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
if (enable == wcd->tx_port_value[port_id])
return 0;
wcd->tx_port_value[port_id] = enable;
if (enable)
list_add_tail(&wcd->tx_chs[port_id].list,
&wcd->dai[dai_id].slim_ch_list);
else
list_del_init(&wcd->tx_chs[port_id].list);
if (enable) {
if (list_empty(&wcd->tx_chs[port_id].list)) {
list_add_tail(&wcd->tx_chs[port_id].list,
&wcd->dai[dai_id].slim_ch_list);
} else {
dev_err(wcd->dev ,"SLIM_TX%d PORT is busy\n", port_id);
return 0;
}
} else {
bool found = false;
list_for_each_entry_safe(ch, c, &wcd->dai[dai_id].slim_ch_list, list) {
if (ch->port == port_id) {
found = true;
list_del_init(&wcd->tx_chs[port_id].list);
break;
}
}
if (!found)
return 0;
}
wcd->tx_port_value[port_id] = enable;
snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update);
return 0;
return 1;
}
static const struct snd_kcontrol_new aif1_slim_cap_mixer[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment