summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-topology.c')
-rw-r--r--sound/soc/soc-topology.c115
1 files changed, 89 insertions, 26 deletions
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 87f75edba3dc..6df3b0d12d87 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -894,7 +894,13 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
}
/* create any TLV data */
- soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
+ err = soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
+ if (err < 0) {
+ dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
+ mc->hdr.name);
+ kfree(sm);
+ continue;
+ }
/* pass control to driver for optional further init */
err = soc_tplg_init_kcontrol(tplg, &kc,
@@ -1118,6 +1124,7 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
struct snd_soc_tplg_ctl_hdr *control_hdr;
+ int ret;
int i;
if (tplg->pass != SOC_TPLG_PASS_MIXER) {
@@ -1146,25 +1153,30 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
case SND_SOC_TPLG_CTL_RANGE:
case SND_SOC_TPLG_DAPM_CTL_VOLSW:
case SND_SOC_TPLG_DAPM_CTL_PIN:
- soc_tplg_dmixer_create(tplg, 1,
- le32_to_cpu(hdr->payload_size));
+ ret = soc_tplg_dmixer_create(tplg, 1,
+ le32_to_cpu(hdr->payload_size));
break;
case SND_SOC_TPLG_CTL_ENUM:
case SND_SOC_TPLG_CTL_ENUM_VALUE:
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
- soc_tplg_denum_create(tplg, 1,
- le32_to_cpu(hdr->payload_size));
+ ret = soc_tplg_denum_create(tplg, 1,
+ le32_to_cpu(hdr->payload_size));
break;
case SND_SOC_TPLG_CTL_BYTES:
- soc_tplg_dbytes_create(tplg, 1,
- le32_to_cpu(hdr->payload_size));
+ ret = soc_tplg_dbytes_create(tplg, 1,
+ le32_to_cpu(hdr->payload_size));
break;
default:
soc_bind_err(tplg, control_hdr, i);
return -EINVAL;
}
+ if (ret < 0) {
+ dev_err(tplg->dev, "ASoC: invalid control\n");
+ return ret;
+ }
+
}
return 0;
@@ -1272,7 +1284,9 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
routes[i]->dobj.index = tplg->index;
list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list);
- soc_tplg_add_route(tplg, routes[i]);
+ ret = soc_tplg_add_route(tplg, routes[i]);
+ if (ret < 0)
+ break;
/* add route, but keep going if some fail */
snd_soc_dapm_add_routes(dapm, routes[i], 1);
@@ -1355,7 +1369,13 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
}
/* create any TLV data */
- soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr);
+ err = soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr);
+ if (err < 0) {
+ dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
+ mc->hdr.name);
+ kfree(sm);
+ continue;
+ }
/* pass control to driver for optional further init */
err = soc_tplg_init_kcontrol(tplg, &kc[i],
@@ -1766,10 +1786,13 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
return 0;
}
-static void set_stream_info(struct snd_soc_pcm_stream *stream,
+static int set_stream_info(struct snd_soc_pcm_stream *stream,
struct snd_soc_tplg_stream_caps *caps)
{
stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
+ if (!stream->stream_name)
+ return -ENOMEM;
+
stream->channels_min = le32_to_cpu(caps->channels_min);
stream->channels_max = le32_to_cpu(caps->channels_max);
stream->rates = le32_to_cpu(caps->rates);
@@ -1777,6 +1800,8 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream,
stream->rate_max = le32_to_cpu(caps->rate_max);
stream->formats = le64_to_cpu(caps->formats);
stream->sig_bits = le32_to_cpu(caps->sig_bits);
+
+ return 0;
}
static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
@@ -1812,20 +1837,29 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
if (dai_drv == NULL)
return -ENOMEM;
- if (strlen(pcm->dai_name))
+ if (strlen(pcm->dai_name)) {
dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
+ if (!dai_drv->name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
dai_drv->id = le32_to_cpu(pcm->dai_id);
if (pcm->playback) {
stream = &dai_drv->playback;
caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
- set_stream_info(stream, caps);
+ ret = set_stream_info(stream, caps);
+ if (ret < 0)
+ goto err;
}
if (pcm->capture) {
stream = &dai_drv->capture;
caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
- set_stream_info(stream, caps);
+ ret = set_stream_info(stream, caps);
+ if (ret < 0)
+ goto err;
}
if (pcm->compress)
@@ -1835,11 +1869,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
if (ret < 0) {
dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
- kfree(dai_drv->playback.stream_name);
- kfree(dai_drv->capture.stream_name);
- kfree(dai_drv->name);
- kfree(dai_drv);
- return ret;
+ goto err;
}
dai_drv->dobj.index = tplg->index;
@@ -1860,6 +1890,14 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
return ret;
}
+ return 0;
+
+err:
+ kfree(dai_drv->playback.stream_name);
+ kfree(dai_drv->capture.stream_name);
+ kfree(dai_drv->name);
+ kfree(dai_drv);
+
return ret;
}
@@ -1916,11 +1954,20 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
if (strlen(pcm->pcm_name)) {
link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
+ if (!link->name || !link->stream_name) {
+ ret = -ENOMEM;
+ goto err;
+ }
}
link->id = le32_to_cpu(pcm->pcm_id);
- if (strlen(pcm->dai_name))
+ if (strlen(pcm->dai_name)) {
link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
+ if (!link->cpus->dai_name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
link->codecs->name = "snd-soc-dummy";
link->codecs->dai_name = "snd-soc-dummy-dai";
@@ -2088,7 +2135,9 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
_pcm = pcm;
} else {
abi_match = false;
- pcm_new_ver(tplg, pcm, &_pcm);
+ ret = pcm_new_ver(tplg, pcm, &_pcm);
+ if (ret < 0)
+ return ret;
}
/* create the FE DAIs and DAI links */
@@ -2436,13 +2485,17 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
if (d->playback) {
stream = &dai_drv->playback;
caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
- set_stream_info(stream, caps);
+ ret = set_stream_info(stream, caps);
+ if (ret < 0)
+ goto err;
}
if (d->capture) {
stream = &dai_drv->capture;
caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];
- set_stream_info(stream, caps);
+ ret = set_stream_info(stream, caps);
+ if (ret < 0)
+ goto err;
}
if (d->flag_mask)
@@ -2454,10 +2507,15 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
if (ret < 0) {
dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
- return ret;
+ goto err;
}
return 0;
+
+err:
+ kfree(dai_drv->playback.stream_name);
+ kfree(dai_drv->capture.stream_name);
+ return ret;
}
/* load physical DAI elements */
@@ -2466,7 +2524,7 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg,
{
struct snd_soc_tplg_dai *dai;
int count;
- int i;
+ int i, ret;
count = le32_to_cpu(hdr->count);
@@ -2481,7 +2539,12 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg,
return -EINVAL;
}
- soc_tplg_dai_config(tplg, dai);
+ ret = soc_tplg_dai_config(tplg, dai);
+ if (ret < 0) {
+ dev_err(tplg->dev, "ASoC: failed to configure DAI\n");
+ return ret;
+ }
+
tplg->pos += (sizeof(*dai) + le32_to_cpu(dai->priv.size));
}
@@ -2589,7 +2652,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
}
/* big endian firmware objects not supported atm */
- if (hdr->magic == SOC_TPLG_MAGIC_BIG_ENDIAN) {
+ if (le32_to_cpu(hdr->magic) == SOC_TPLG_MAGIC_BIG_ENDIAN) {
dev_err(tplg->dev,
"ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
tplg->pass, hdr->magic,