[alsa-devel] [PATCH v2 13/13] ASoC: topology: Add support for BE and CC DAI Links

mengdong.lin at linux.intel.com mengdong.lin at linux.intel.com
Thu Nov 5 11:00:14 CET 2015


From: Vedang Patel <vedang.patel at intel.com>

Adding support to modify already existing BE and CC DAI Links.
The links are matches using unique id (be_id) of the links.

Now, the params member in the snd_soc_dai_link struct will be
populated with stream related information.

Signed-off-by: Vedang Patel <vedang.patel at intel.com>
Signed-off-by: Mengdong Lin <mengdong.lin at linux.intel.com>

diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
index 6324537..f37f5d8 100644
--- a/include/sound/soc-topology.h
+++ b/include/sound/soc-topology.h
@@ -40,6 +40,7 @@ enum snd_soc_dobj_type {
 	SND_SOC_DOBJ_BYTES,
 	SND_SOC_DOBJ_PCM,
 	SND_SOC_DOBJ_DAI_LINK,
+	SND_SOC_DOBJ_BACKEND_LINK,
 	SND_SOC_DOBJ_CODEC_LINK,
 	SND_SOC_DOBJ_WIDGET,
 };
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 31fe60a..875c361 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -992,6 +992,9 @@ struct snd_soc_dai_link {
 	const struct snd_soc_pcm_stream *params;
 	unsigned int num_params;
 
+	/* Stores HW params. Used by topology core. */
+	const struct snd_pcm_hardware *hw_params;
+
 	unsigned int dai_fmt;           /* format to set on init */
 
 	enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index d07c6b0..83c8dd8 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -48,9 +48,11 @@
 #define SOC_TPLG_PASS_PCM_DAI		4
 #define SOC_TPLG_PASS_GRAPH		5
 #define SOC_TPLG_PASS_PINS		6
+#define SOC_TPLG_PASS_BE_LINK		7
+#define SOC_TPLG_PASS_CC_LINK		8
 
 #define SOC_TPLG_PASS_START	SOC_TPLG_PASS_MANIFEST
-#define SOC_TPLG_PASS_END	SOC_TPLG_PASS_PINS
+#define SOC_TPLG_PASS_END	SOC_TPLG_PASS_CC_LINK
 
 struct soc_tplg {
 	const struct firmware *fw;
@@ -263,6 +265,8 @@ static enum snd_soc_dobj_type get_dobj_type(struct snd_soc_tplg_hdr *hdr,
 		return SND_SOC_DOBJ_PCM;
 	case SND_SOC_TPLG_TYPE_CODEC_LINK:
 		return SND_SOC_DOBJ_CODEC_LINK;
+	case SND_SOC_TPLG_TYPE_BACKEND_LINK:
+		return SND_SOC_DOBJ_BACKEND_LINK;
 	default:
 		return SND_SOC_DOBJ_NONE;
 	}
@@ -522,6 +526,21 @@ static void remove_pcm_dai(struct snd_soc_component *comp,
 	kfree(dai);
 }
 
+static void soc_tplg_free_be_cc_params(struct snd_soc_component *comp,
+	struct snd_soc_dobj *dobj, int pass)
+{
+	struct snd_soc_card *card = comp->card;
+	struct snd_soc_dai_link *dai_link = card->dai_link;
+	int i, num_links = card->num_links;
+
+	if (pass != SOC_TPLG_PASS_BE_LINK || pass != SOC_TPLG_PASS_CC_LINK)
+		return;
+
+	/* loop through all dai_links. */
+	for (i = 0; i < num_links; i++)
+		kfree(dai_link->hw_params);
+
+}
 /* bind a kcontrol to it's IO handlers */
 static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
 	struct snd_kcontrol_new *k,
@@ -1701,6 +1720,89 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
 	return 0;
 }
 
+static void soc_tplg_make_hw_params(struct snd_pcm_hardware *hw,
+	struct snd_soc_tplg_stream *streams, int num_streams)
+{
+	struct snd_soc_tplg_stream *stream;
+	unsigned int rate;
+	int i;
+
+	for (i = 0; i < num_streams; i++) {
+		stream = streams + i;
+		hw->formats |= stream->format;
+
+		hw->rates |= stream->rate;
+		rate = snd_pcm_rate_bit_to_rate(stream->rate);
+		if (!hw->rate_min || hw->rate_min > rate)
+			hw->rate_min = rate;
+		if (hw->rate_max < rate)
+			hw->rate_max = rate;
+
+		if (!hw->channels_min || hw->channels_min > stream->channels)
+			hw->channels_min = stream->channels;
+		if (hw->channels_max < stream->channels)
+			hw->channels_max = stream->channels;
+
+		if (!hw->period_bytes_min
+			|| hw->period_bytes_min > stream->period_bytes)
+			hw->period_bytes_min = stream->period_bytes;
+		if (hw->period_bytes_max < stream->period_bytes)
+			hw->period_bytes_max = stream->period_bytes;
+
+		if (hw->buffer_bytes_max < stream->buffer_bytes)
+			hw->buffer_bytes_max = stream->buffer_bytes;
+		}
+}
+
+/* modify already existing backend links and codec links. */
+static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
+	struct snd_soc_tplg_hdr *hdr)
+{
+	int i, j;
+	struct snd_soc_tplg_link_config *link;
+	struct snd_soc_card *card = tplg->comp->card;
+	struct snd_soc_dai_link *dai_link = card->dai_link;
+	struct snd_pcm_hardware *pcm_hw;
+	int count = hdr->count, num_dailinks = card->num_links;
+
+	if (tplg->pass != SOC_TPLG_PASS_BE_LINK &&
+		tplg->pass != SOC_TPLG_PASS_CC_LINK)
+		return 0;
+
+	for (i = 0; i < count; i++) {
+		link = (struct snd_soc_tplg_link_config *) tplg->pos;
+		/**
+		 * The machine driver will initially create BE and CC Links.
+		 * In topology, we are searching for the existing BE Link
+		 * by it unique id (be_id).
+		 */
+		for (j = 0; j < num_dailinks; j++) {
+			if (dai_link[j].be_id == link->id)
+				break;
+		}
+
+		if (j == num_dailinks && dai_link[j].be_id != link->id) {
+			dev_err(tplg->dev,
+				"ASoC: cannot find Back End DAI with id %d",
+				link->id);
+			continue;
+		}
+
+		/* copy the data from tplg_elem to BE/CC DAI Link. */
+		pcm_hw = kzalloc(sizeof(struct snd_pcm_hardware), GFP_KERNEL);
+		if (!pcm_hw)
+			return -ENOMEM;
+		soc_tplg_make_hw_params(pcm_hw,
+			link->stream, link->num_streams);
+		dai_link[j].hw_params = pcm_hw;
+
+		tplg->pos += sizeof(struct snd_soc_tplg_link_config);
+	}
+
+
+	return 0;
+}
+
 static int soc_tplg_manifest_load(struct soc_tplg *tplg,
 	struct snd_soc_tplg_hdr *hdr)
 {
@@ -1791,8 +1893,10 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
 		return soc_tplg_dapm_widget_elems_load(tplg, hdr);
 	case SND_SOC_TPLG_TYPE_PCM:
 	case SND_SOC_TPLG_TYPE_DAI_LINK:
-	case SND_SOC_TPLG_TYPE_CODEC_LINK:
 		return soc_tplg_pcm_elems_load(tplg, hdr);
+	case SND_SOC_TPLG_TYPE_BACKEND_LINK:
+	case SND_SOC_TPLG_TYPE_CODEC_LINK:
+		return soc_tplg_link_elems_load(tplg, hdr);
 	case SND_SOC_TPLG_TYPE_MANIFEST:
 		return soc_tplg_manifest_load(tplg, hdr);
 	default:
@@ -1950,9 +2054,12 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
 				break;
 			case SND_SOC_DOBJ_PCM:
 			case SND_SOC_DOBJ_DAI_LINK:
-			case SND_SOC_DOBJ_CODEC_LINK:
 				remove_pcm_dai(comp, dobj, pass);
 				break;
+			case SND_SOC_DOBJ_BACKEND_LINK:
+			case SND_SOC_DOBJ_CODEC_LINK:
+				soc_tplg_free_be_cc_params(comp, dobj, pass);
+				break;
 			default:
 				dev_err(comp->dev, "ASoC: invalid component type %d for removal\n",
 					dobj->type);
-- 
1.9.1



More information about the Alsa-devel mailing list