Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/sound/soc-dpcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ struct snd_soc_dpcm {
struct list_head list_be;
struct list_head list_fe;

/*
* BE reference taken for the FE by START, RESUME or PAUSE_RELEASE,
* only accessed from the trigger path of the FE
*/
bool trigger_ref;

#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_state;
#endif
Expand Down
23 changes: 22 additions & 1 deletion sound/soc/soc-component.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <linux/bitops.h>
#include "soc-internal.h"

#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
static inline int _soc_component_ret(struct snd_soc_component *component, const char *func, int ret)
Expand Down Expand Up @@ -456,6 +457,7 @@ int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
int unwind_cmd;
int i, ret;

for_each_rtd_components(rtd, i, component) {
Expand All @@ -464,11 +466,30 @@ int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd)
ret = component->driver->compress_ops->trigger(
component, cstream, cmd);
if (ret < 0)
return soc_component_ret(component, ret);
goto unwind;
}
}

return 0;

unwind:
ret = soc_component_ret(component, ret);

unwind_cmd = snd_soc_trigger_unwind_cmd(cmd);
if (unwind_cmd < 0)
return ret;

/* Unwind the components that have been triggered before the failing one */
while (--i >= 0) {
component = rtd->components[i];
if (component->driver->compress_ops &&
component->driver->compress_ops->trigger)
component->driver->compress_ops->trigger(component,
cstream,
unwind_cmd);
}

return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger);

Expand Down
45 changes: 34 additions & 11 deletions sound/soc/soc-compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
dpcm_path_put(&list);

fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
fe->dpcm[stream].fe_pause = false;
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;

snd_soc_runtime_activate(fe, stream);
Expand Down Expand Up @@ -365,6 +366,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
int unwind_cmd;
int ret;

snd_soc_dpcm_mutex_lock(rtd);
Expand All @@ -374,8 +376,12 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
goto out;

ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
if (ret < 0)
if (ret < 0) {
unwind_cmd = snd_soc_trigger_unwind_cmd(cmd);
if (unwind_cmd >= 0)
snd_soc_component_compr_trigger(cstream, unwind_cmd);
goto out;
}

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
Expand All @@ -391,26 +397,45 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
return ret;
}

static int soc_compr_trigger_fe_only(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
int unwind_cmd;
int ret;

ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
if (ret < 0)
return ret;

ret = snd_soc_component_compr_trigger(cstream, cmd);
if (ret < 0) {
unwind_cmd = snd_soc_trigger_unwind_cmd(cmd);
if (unwind_cmd >= 0)
snd_soc_dai_compr_trigger(cpu_dai, cstream, unwind_cmd);
}

return ret;
}

static int soc_compr_trigger_fe_be(struct snd_compr_stream *cstream, int cmd,
bool fe_first)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
int unwind_cmd = snd_soc_trigger_unwind_cmd(cmd);
int ret;

if (fe_first) {
dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
fe->dai_link->name, cmd);

ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
if (ret < 0)
goto out;

ret = snd_soc_component_compr_trigger(cstream, cmd);
ret = soc_compr_trigger_fe_only(cstream, cmd);
if (ret < 0)
goto out;

ret = dpcm_be_dai_trigger(fe, cstream->direction, cmd);
if (ret < 0 && unwind_cmd >= 0)
soc_compr_trigger_fe_only(cstream, unwind_cmd);
} else {
dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
fe->dai_link->name, cmd);
Expand All @@ -419,11 +444,9 @@ static int soc_compr_trigger_fe_be(struct snd_compr_stream *cstream, int cmd,
if (ret < 0)
goto out;

ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
ret = soc_compr_trigger_fe_only(cstream, cmd);
if (ret < 0)
goto out;

ret = snd_soc_component_compr_trigger(cstream, cmd);
dpcm_be_dai_trigger_unwind(fe, cstream->direction, cmd);
}

out:
Expand Down
24 changes: 24 additions & 0 deletions sound/soc/soc-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,28 @@ struct clk *snd_soc_dai_get_bclk(struct snd_soc_dai *dai);
unsigned int snd_soc_dai_get_bclk_ratio(struct snd_soc_dai *dai);
void snd_soc_dai_active_update(struct snd_soc_dai *dai, int stream, int action);

/*
* In soc-pcm
*/
void dpcm_be_dai_trigger_unwind(struct snd_soc_pcm_runtime *fe, int stream,
int cmd);

/*
* Get the trigger command to unwind a failed START, RESUME or PAUSE_RELEASE.
* Returns -EINVAL for commands that are not unwound.
*/
static inline int snd_soc_trigger_unwind_cmd(int cmd)
{
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
return SNDRV_PCM_TRIGGER_STOP;
case SNDRV_PCM_TRIGGER_RESUME:
return SNDRV_PCM_TRIGGER_SUSPEND;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
return SNDRV_PCM_TRIGGER_PAUSE_PUSH;
default:
return -EINVAL;
}
}

#endif /* __SOC_INTERNAL_H */
Loading
Loading