Unverified Commit 67aa59af authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: topology: Fixes and cleanups

Merge series from Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>:

Following is series of fixes and cleanups for core topology code. Few
patches fixing various problems all around and few fixing function
names.
parents 7f27be23 31e92739
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ struct snd_soc_dobj {
	enum snd_soc_dobj_type type;
	unsigned int index;	/* objects can belong in different groups */
	struct list_head list;
	struct snd_soc_tplg_ops *ops;
	int (*unload)(struct snd_soc_component *comp, struct snd_soc_dobj *dobj);
	union {
		struct snd_soc_dobj_control control;
		struct snd_soc_dobj_widget widget;
+73 −110
Original line number Diff line number Diff line
@@ -44,9 +44,8 @@
#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
@@ -77,9 +76,6 @@ struct soc_tplg {
	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)
@@ -186,7 +182,7 @@ static const struct soc_tplg_map dapm_map[] = {
	{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;
@@ -199,7 +195,7 @@ static int tplc_chan_get_reg(struct soc_tplg *tplg,
	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;
@@ -354,69 +350,37 @@ static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
				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;
@@ -427,8 +391,8 @@ static void remove_widget(struct snd_soc_component *comp,
	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;
@@ -444,7 +408,7 @@ static void remove_widget(struct snd_soc_component *comp,
}

/* 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 =
@@ -454,8 +418,8 @@ static void remove_dai(struct snd_soc_component *comp,
	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)
@@ -465,7 +429,7 @@ static void remove_dai(struct snd_soc_component *comp,
}

/* 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 =
@@ -474,8 +438,8 @@ static void remove_link(struct snd_soc_component *comp,
	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,
@@ -489,11 +453,11 @@ static void remove_backend_link(struct snd_soc_component *comp,
	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
	 */
@@ -714,7 +678,8 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size)

	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 */
@@ -725,7 +690,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size)
	}

	/* 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;
@@ -780,18 +745,19 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
	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 */
@@ -809,7 +775,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
	}

	/* 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;
@@ -927,16 +893,17 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size)
	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)) {
@@ -977,7 +944,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size)
	}

	/* 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;
@@ -1113,7 +1080,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,

		/* 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->control_unload;
		route->dobj.index = tplg->index;
		list_add(&route->dobj.list, &tplg->comp->dobj_list);

@@ -1161,13 +1129,13 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_
	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);
@@ -1193,7 +1161,7 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_
	}

	/* 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);
@@ -1233,10 +1201,10 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k
	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);
@@ -1277,7 +1245,7 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k
	}

	/* 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);
@@ -1329,7 +1297,7 @@ static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_
	}

	/* 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);
@@ -1479,7 +1447,8 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,

	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);

@@ -1493,7 +1462,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
	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);
@@ -1567,7 +1536,7 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
		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,
@@ -1657,8 +1626,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
	}

	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 */
@@ -1727,8 +1697,9 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
	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);
@@ -2135,8 +2106,9 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,

	/* 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;
@@ -2390,12 +2362,9 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
}

/* 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",
@@ -2404,7 +2373,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
		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),
@@ -2446,7 +2415,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
		return -EINVAL;
	}

	return 1;
	return 0;
}

/* check header type and call appropriate handler */
@@ -2527,13 +2496,11 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg)
		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 */
@@ -2627,26 +2594,22 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
			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:
				/*