#define SOC_TPLG_PASS_WIDGET 3
#define SOC_TPLG_PASS_PCM_DAI 4
#define SOC_TPLG_PASS_GRAPH 5
-#define SOC_TPLG_PASS_PINS 6
-#define SOC_TPLG_PASS_BE_DAI 7
-#define SOC_TPLG_PASS_LINK 8
+#define SOC_TPLG_PASS_BE_DAI 6
+#define SOC_TPLG_PASS_LINK 7
#define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST
#define SOC_TPLG_PASS_END SOC_TPLG_PASS_LINK
struct snd_soc_tplg_ops *ops;
};
-static int soc_tplg_process_headers(struct soc_tplg *tplg);
-static int soc_tplg_complete(struct soc_tplg *tplg);
-
/* check we dont overflow the data for this control chunk */
static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
unsigned int count, size_t bytes, const char *elem_type)
{SND_SOC_TPLG_DAPM_DECODER, snd_soc_dapm_decoder},
};
-static int tplc_chan_get_reg(struct soc_tplg *tplg,
+static int tplg_chan_get_reg(struct soc_tplg *tplg,
struct snd_soc_tplg_channel *chan, int map)
{
int i;
return -EINVAL;
}
-static int tplc_chan_get_shift(struct soc_tplg *tplg,
+static int tplg_chan_get_shift(struct soc_tplg *tplg,
struct snd_soc_tplg_channel *chan, int map)
{
int i;
tplg->dev, k, comp->name_prefix, comp, kcontrol);
}
-/* remove a mixer kcontrol */
-static void remove_mixer(struct snd_soc_component *comp,
- struct snd_soc_dobj *dobj, int pass)
-{
- struct snd_card *card = comp->card->snd_card;
-
- if (pass != SOC_TPLG_PASS_CONTROL)
- return;
-
- if (dobj->ops && dobj->ops->control_unload)
- dobj->ops->control_unload(comp, dobj);
-
- snd_ctl_remove(card, dobj->control.kcontrol);
- list_del(&dobj->list);
-}
-
-/* remove an enum kcontrol */
-static void remove_enum(struct snd_soc_component *comp,
- struct snd_soc_dobj *dobj, int pass)
-{
- struct snd_card *card = comp->card->snd_card;
-
- if (pass != SOC_TPLG_PASS_CONTROL)
- return;
-
- if (dobj->ops && dobj->ops->control_unload)
- dobj->ops->control_unload(comp, dobj);
-
- snd_ctl_remove(card, dobj->control.kcontrol);
- list_del(&dobj->list);
-}
-
-/* remove a byte kcontrol */
-static void remove_bytes(struct snd_soc_component *comp,
- struct snd_soc_dobj *dobj, int pass)
+/* remove kcontrol */
+static void soc_tplg_remove_kcontrol(struct snd_soc_component *comp, struct snd_soc_dobj *dobj,
+ int pass)
{
struct snd_card *card = comp->card->snd_card;
if (pass != SOC_TPLG_PASS_CONTROL)
return;
- if (dobj->ops && dobj->ops->control_unload)
- dobj->ops->control_unload(comp, dobj);
+ if (dobj->unload)
+ dobj->unload(comp, dobj);
snd_ctl_remove(card, dobj->control.kcontrol);
list_del(&dobj->list);
}
/* remove a route */
-static void remove_route(struct snd_soc_component *comp,
+static void soc_tplg_remove_route(struct snd_soc_component *comp,
struct snd_soc_dobj *dobj, int pass)
{
if (pass != SOC_TPLG_PASS_GRAPH)
return;
- if (dobj->ops && dobj->ops->dapm_route_unload)
- dobj->ops->dapm_route_unload(comp, dobj);
+ if (dobj->unload)
+ dobj->unload(comp, dobj);
list_del(&dobj->list);
}
/* remove a widget and it's kcontrols - routes must be removed first */
-static void remove_widget(struct snd_soc_component *comp,
+static void soc_tplg_remove_widget(struct snd_soc_component *comp,
struct snd_soc_dobj *dobj, int pass)
{
struct snd_card *card = comp->card->snd_card;
if (pass != SOC_TPLG_PASS_WIDGET)
return;
- if (dobj->ops && dobj->ops->widget_unload)
- dobj->ops->widget_unload(comp, dobj);
+ if (dobj->unload)
+ dobj->unload(comp, dobj);
if (!w->kcontrols)
goto free_news;
}
/* remove DAI configurations */
-static void remove_dai(struct snd_soc_component *comp,
+static void soc_tplg_remove_dai(struct snd_soc_component *comp,
struct snd_soc_dobj *dobj, int pass)
{
struct snd_soc_dai_driver *dai_drv =
if (pass != SOC_TPLG_PASS_PCM_DAI)
return;
- if (dobj->ops && dobj->ops->dai_unload)
- dobj->ops->dai_unload(comp, dobj);
+ if (dobj->unload)
+ dobj->unload(comp, dobj);
for_each_component_dais_safe(comp, dai, _dai)
if (dai->driver == dai_drv)
}
/* remove link configurations */
-static void remove_link(struct snd_soc_component *comp,
+static void soc_tplg_remove_link(struct snd_soc_component *comp,
struct snd_soc_dobj *dobj, int pass)
{
struct snd_soc_dai_link *link =
if (pass != SOC_TPLG_PASS_PCM_DAI)
return;
- if (dobj->ops && dobj->ops->link_unload)
- dobj->ops->link_unload(comp, dobj);
+ if (dobj->unload)
+ dobj->unload(comp, dobj);
list_del(&dobj->list);
snd_soc_remove_pcm_runtime(comp->card,
if (pass != SOC_TPLG_PASS_LINK)
return;
- if (dobj->ops && dobj->ops->link_unload)
- dobj->ops->link_unload(comp, dobj);
+ if (dobj->unload)
+ dobj->unload(comp, dobj);
/*
- * We don't free the link here as what remove_link() do since BE
+ * We don't free the link here as what soc_tplg_remove_link() do since BE
* links are not allocated by topology.
* We however need to reset the dobj type to its initial values
*/
sbe->max = le32_to_cpu(be->max);
sbe->dobj.type = SND_SOC_DOBJ_BYTES;
- sbe->dobj.ops = tplg->ops;
+ if (tplg->ops)
+ sbe->dobj.unload = tplg->ops->control_unload;
INIT_LIST_HEAD(&sbe->dobj.list);
/* map io handlers */
}
/* pass control to driver for optional further init */
- ret = soc_tplg_control_load(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *)be);
+ ret = soc_tplg_control_load(tplg, &kc, &be->hdr);
if (ret < 0) {
dev_err(tplg->dev, "ASoC: failed to init %s\n", be->hdr.name);
goto err;
kc.access = le32_to_cpu(mc->hdr.access);
/* we only support FL/FR channel mapping atm */
- sm->reg = tplc_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL);
- sm->rreg = tplc_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR);
- sm->shift = tplc_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL);
- sm->rshift = tplc_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR);
+ sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL);
+ sm->rreg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR);
+ sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL);
+ sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR);
sm->max = le32_to_cpu(mc->max);
sm->min = le32_to_cpu(mc->min);
sm->invert = le32_to_cpu(mc->invert);
sm->platform_max = le32_to_cpu(mc->platform_max);
sm->dobj.index = tplg->index;
- sm->dobj.ops = tplg->ops;
sm->dobj.type = SND_SOC_DOBJ_MIXER;
+ if (tplg->ops)
+ sm->dobj.unload = tplg->ops->control_unload;
INIT_LIST_HEAD(&sm->dobj.list);
/* map io handlers */
}
/* pass control to driver for optional further init */
- ret = soc_tplg_control_load(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *)mc);
+ ret = soc_tplg_control_load(tplg, &kc, &mc->hdr);
if (ret < 0) {
dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name);
goto err;
kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
kc.access = le32_to_cpu(ec->hdr.access);
- se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
- se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
+ se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
+ se->shift_l = tplg_chan_get_shift(tplg, ec->channel,
SNDRV_CHMAP_FL);
- se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
+ se->shift_r = tplg_chan_get_shift(tplg, ec->channel,
SNDRV_CHMAP_FL);
se->mask = le32_to_cpu(ec->mask);
se->dobj.index = tplg->index;
se->dobj.type = SND_SOC_DOBJ_ENUM;
- se->dobj.ops = tplg->ops;
+ if (tplg->ops)
+ se->dobj.unload = tplg->ops->control_unload;
INIT_LIST_HEAD(&se->dobj.list);
switch (le32_to_cpu(ec->hdr.ops.info)) {
}
/* pass control to driver for optional further init */
- ret = soc_tplg_control_load(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *)ec);
+ ret = soc_tplg_control_load(tplg, &kc, &ec->hdr);
if (ret < 0) {
dev_err(tplg->dev, "ASoC: failed to init %s\n", ec->hdr.name);
goto err;
/* add route dobj to dobj_list */
route->dobj.type = SND_SOC_DOBJ_GRAPH;
- route->dobj.ops = tplg->ops;
+ if (tplg->ops)
+ route->dobj.unload = tplg->ops->dapm_route_unload;
route->dobj.index = tplg->index;
list_add(&route->dobj.list, &tplg->comp->dobj_list);
kc->access = le32_to_cpu(mc->hdr.access);
/* we only support FL/FR channel mapping atm */
- sm->reg = tplc_chan_get_reg(tplg, mc->channel,
+ sm->reg = tplg_chan_get_reg(tplg, mc->channel,
SNDRV_CHMAP_FL);
- sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
+ sm->rreg = tplg_chan_get_reg(tplg, mc->channel,
SNDRV_CHMAP_FR);
- sm->shift = tplc_chan_get_shift(tplg, mc->channel,
+ sm->shift = tplg_chan_get_shift(tplg, mc->channel,
SNDRV_CHMAP_FL);
- sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
+ sm->rshift = tplg_chan_get_shift(tplg, mc->channel,
SNDRV_CHMAP_FR);
sm->max = le32_to_cpu(mc->max);
}
/* pass control to driver for optional further init */
- err = soc_tplg_control_load(tplg, kc, (struct snd_soc_tplg_ctl_hdr *)mc);
+ err = soc_tplg_control_load(tplg, kc, &mc->hdr);
if (err < 0) {
dev_err(tplg->dev, "ASoC: failed to init %s\n",
mc->hdr.name);
kc->access = le32_to_cpu(ec->hdr.access);
/* we only support FL/FR channel mapping atm */
- se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
- se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
+ se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
+ se->shift_l = tplg_chan_get_shift(tplg, ec->channel,
SNDRV_CHMAP_FL);
- se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
+ se->shift_r = tplg_chan_get_shift(tplg, ec->channel,
SNDRV_CHMAP_FR);
se->items = le32_to_cpu(ec->items);
}
/* pass control to driver for optional further init */
- err = soc_tplg_control_load(tplg, kc, (struct snd_soc_tplg_ctl_hdr *)ec);
+ err = soc_tplg_control_load(tplg, kc, &ec->hdr);
if (err < 0) {
dev_err(tplg->dev, "ASoC: failed to init %s\n",
ec->hdr.name);
}
/* pass control to driver for optional further init */
- err = soc_tplg_control_load(tplg, kc, (struct snd_soc_tplg_ctl_hdr *)be);
+ err = soc_tplg_control_load(tplg, kc, &be->hdr);
if (err < 0) {
dev_err(tplg->dev, "ASoC: failed to init %s\n",
be->hdr.name);
/* card dapm mutex is held by the core if we are loading topology
* data during sound card init. */
- if (card->instantiated)
+ if (snd_soc_card_is_instantiated(card))
widget = snd_soc_dapm_new_control(dapm, &template);
else
widget = snd_soc_dapm_new_control_unlocked(dapm, &template);
widget->dobj.type = SND_SOC_DOBJ_WIDGET;
widget->dobj.widget.kcontrol_type = kcontrol_type;
- widget->dobj.ops = tplg->ops;
+ if (tplg->ops)
+ widget->dobj.unload = tplg->ops->widget_unload;
widget->dobj.index = tplg->index;
list_add(&widget->dobj.list, &tplg->comp->dobj_list);
return 0;
ready_err:
- remove_widget(widget->dapm->component, &widget->dobj, SOC_TPLG_PASS_WIDGET);
+ soc_tplg_remove_widget(widget->dapm->component, &widget->dobj, SOC_TPLG_PASS_WIDGET);
snd_soc_dapm_free_widget(widget);
hdr_err:
kfree(template.sname);
/* Card might not have been registered at this point.
* If so, just return success.
*/
- if (!card || !card->instantiated) {
+ if (!snd_soc_card_is_instantiated(card)) {
dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
" widget card binding deferred\n");
return 0;
dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n",
ret);
- return 0;
+ return ret;
}
static int set_stream_info(struct soc_tplg *tplg, struct snd_soc_pcm_stream *stream,
}
dai_drv->dobj.index = tplg->index;
- dai_drv->dobj.ops = tplg->ops;
dai_drv->dobj.type = SND_SOC_DOBJ_PCM;
+ if (tplg->ops)
+ dai_drv->dobj.unload = tplg->ops->dai_unload;
list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
/* register the DAI to the component */
link->num_platforms = 1;
link->dobj.index = tplg->index;
- link->dobj.ops = tplg->ops;
link->dobj.type = SND_SOC_DOBJ_DAI_LINK;
+ if (tplg->ops)
+ link->dobj.unload = tplg->ops->link_unload;
if (strlen(pcm->pcm_name)) {
link->name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
/* for unloading it in snd_soc_tplg_component_remove */
link->dobj.index = tplg->index;
- link->dobj.ops = tplg->ops;
link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK;
+ if (tplg->ops)
+ link->dobj.unload = tplg->ops->link_unload;
list_add(&link->dobj.list, &tplg->comp->dobj_list);
return 0;
}
/* validate header magic, size and type */
-static int soc_valid_header(struct soc_tplg *tplg,
+static int soc_tplg_valid_header(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
- if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
- return 0;
-
if (le32_to_cpu(hdr->size) != sizeof(*hdr)) {
dev_err(tplg->dev,
"ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n",
return -EINVAL;
}
- if (soc_tplg_get_hdr_offset(tplg) + hdr->payload_size >= tplg->fw->size) {
+ if (soc_tplg_get_hdr_offset(tplg) + le32_to_cpu(hdr->payload_size) >= tplg->fw->size) {
dev_err(tplg->dev,
"ASoC: invalid header of type %d at offset %ld payload_size %d\n",
le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg),
return -EINVAL;
}
- return 1;
+ return 0;
}
/* check header type and call appropriate handler */
while (!soc_tplg_is_eof(tplg)) {
/* make sure header is valid before loading */
- ret = soc_valid_header(tplg, hdr);
+ ret = soc_tplg_valid_header(tplg, hdr);
if (ret < 0) {
dev_err(tplg->dev,
"ASoC: topology: invalid header: %d\n", ret);
return ret;
- } else if (ret == 0) {
- break;
}
/* load the header object */
list) {
switch (dobj->type) {
- case SND_SOC_DOBJ_MIXER:
- remove_mixer(comp, dobj, pass);
- break;
- case SND_SOC_DOBJ_ENUM:
- remove_enum(comp, dobj, pass);
- break;
case SND_SOC_DOBJ_BYTES:
- remove_bytes(comp, dobj, pass);
+ case SND_SOC_DOBJ_ENUM:
+ case SND_SOC_DOBJ_MIXER:
+ soc_tplg_remove_kcontrol(comp, dobj, pass);
break;
case SND_SOC_DOBJ_GRAPH:
- remove_route(comp, dobj, pass);
+ soc_tplg_remove_route(comp, dobj, pass);
break;
case SND_SOC_DOBJ_WIDGET:
- remove_widget(comp, dobj, pass);
+ soc_tplg_remove_widget(comp, dobj, pass);
break;
case SND_SOC_DOBJ_PCM:
- remove_dai(comp, dobj, pass);
+ soc_tplg_remove_dai(comp, dobj, pass);
break;
case SND_SOC_DOBJ_DAI_LINK:
- remove_link(comp, dobj, pass);
+ soc_tplg_remove_link(comp, dobj, pass);
break;
case SND_SOC_DOBJ_BACKEND_LINK:
/*