summaryrefslogtreecommitdiff
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.c141
1 files changed, 104 insertions, 37 deletions
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 575da6aba807..6df3b0d12d87 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -251,7 +251,7 @@ static int soc_tplg_vendor_load_(struct soc_tplg *tplg,
{
int ret = 0;
- if (tplg->comp && tplg->ops && tplg->ops->vendor_load)
+ if (tplg->ops && tplg->ops->vendor_load)
ret = tplg->ops->vendor_load(tplg->comp, tplg->index, hdr);
else {
dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
@@ -283,7 +283,7 @@ static int soc_tplg_vendor_load(struct soc_tplg *tplg,
static int soc_tplg_widget_load(struct soc_tplg *tplg,
struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
{
- if (tplg->comp && tplg->ops && tplg->ops->widget_load)
+ if (tplg->ops && tplg->ops->widget_load)
return tplg->ops->widget_load(tplg->comp, tplg->index, w,
tplg_w);
@@ -295,7 +295,7 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
static int soc_tplg_widget_ready(struct soc_tplg *tplg,
struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
{
- if (tplg->comp && tplg->ops && tplg->ops->widget_ready)
+ if (tplg->ops && tplg->ops->widget_ready)
return tplg->ops->widget_ready(tplg->comp, tplg->index, w,
tplg_w);
@@ -307,7 +307,7 @@ static int soc_tplg_dai_load(struct soc_tplg *tplg,
struct snd_soc_dai_driver *dai_drv,
struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
{
- if (tplg->comp && tplg->ops && tplg->ops->dai_load)
+ if (tplg->ops && tplg->ops->dai_load)
return tplg->ops->dai_load(tplg->comp, tplg->index, dai_drv,
pcm, dai);
@@ -318,7 +318,7 @@ static int soc_tplg_dai_load(struct soc_tplg *tplg,
static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg)
{
- if (tplg->comp && tplg->ops && tplg->ops->link_load)
+ if (tplg->ops && tplg->ops->link_load)
return tplg->ops->link_load(tplg->comp, tplg->index, link, cfg);
return 0;
@@ -327,7 +327,7 @@ static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
/* tell the component driver that all firmware has been loaded in this request */
static void soc_tplg_complete(struct soc_tplg *tplg)
{
- if (tplg->comp && tplg->ops && tplg->ops->complete)
+ if (tplg->ops && tplg->ops->complete)
tplg->ops->complete(tplg->comp);
}
@@ -362,7 +362,7 @@ static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
struct snd_soc_component *comp = tplg->comp;
return soc_tplg_add_dcontrol(comp->card->snd_card,
- comp->dev, k, NULL, comp, kcontrol);
+ comp->dev, k, comp->name_prefix, comp, kcontrol);
}
/* remove a mixer kcontrol */
@@ -684,7 +684,7 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event);
static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
{
- if (tplg->comp && tplg->ops && tplg->ops->control_load)
+ if (tplg->ops && tplg->ops->control_load)
return tplg->ops->control_load(tplg->comp, tplg->index, k,
hdr);
@@ -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;
@@ -1174,7 +1186,7 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
static int soc_tplg_add_route(struct soc_tplg *tplg,
struct snd_soc_dapm_route *route)
{
- if (tplg->comp && tplg->ops && tplg->ops->dapm_route_load)
+ if (tplg->ops && tplg->ops->dapm_route_load)
return tplg->ops->dapm_route_load(tplg->comp, tplg->index,
route);
@@ -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));
}
@@ -2564,7 +2627,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
}
/* pass control to component driver for optional further init */
- if (tplg->comp && tplg->ops && tplg->ops->manifest)
+ if (tplg->ops && tplg->ops->manifest)
ret = tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
if (!abi_match) /* free the duplicated one */
@@ -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,
@@ -2736,6 +2799,10 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
struct soc_tplg tplg;
int ret;
+ /* component needs to exist to keep and reference data while parsing */
+ if (!comp)
+ return -EINVAL;
+
/* setup parsing context */
memset(&tplg, 0, sizeof(tplg));
tplg.fw = fw;
@@ -2774,7 +2841,7 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
{
struct snd_soc_dapm_widget *w, *next_w;
- list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
+ for_each_card_widgets_safe(dapm->card, w, next_w) {
/* make sure we are a widget with correct context */
if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)