From 3176d6bd70861f780821b49617b141c9a1fb0fa3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 22 Jun 2018 21:09:39 -0700 Subject: [PATCH 1/6] ASoC: add "virtual" flag to dai link structure Hostless pipelines lack a FE dai that is used to establish a path to the BE and enable the codecs. Virtual FE dai links can be used in such cases to establish a connection to the BE. This patch adds a new flag named "virtual" to the dai link structure that will be used to check if a dai link is virtual. Signed-off-by: Ranjani Sridharan --- include/sound/soc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 71a745fa8131d4..c310a3fdc90651 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1134,6 +1134,17 @@ struct snd_soc_dai_link { /* Do not create a PCM for this DAI link (Backend link) */ unsigned int ignore:1; + /* + * virtual FE link + * This flag indicates that there is no PCM device registered with ALSA + * This is intended to be used for establishing a connection to the + * BE DAI in the case of hostless pipelines such as, + * DSP component -> codec, ex: tone generator -> codec + * This connection will be established at runtime by triggering the + * hostless pipeline with a kcontrol attached to the component. + */ + unsigned int virtual:1; + struct list_head list; /* DAI link list of the soc card */ struct snd_soc_dobj dobj; /* For topology */ }; From 771505cf3d25ec445d07c2ac99d668fc19cce48e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 22 Jun 2018 21:13:45 -0700 Subject: [PATCH 2/6] ASoC: pcm: add methods to create/remove virtual dai link This patch adds the methods for create a virtual FE dal link and add it to the sound card. It also adds the method to free the virtual FE connected to the card. Signed-off-by: Ranjani Sridharan --- include/sound/soc-dpcm.h | 5 +- sound/soc/soc-pcm.c | 109 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 806059052bfcca..0373d79a8985c8 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -158,5 +158,8 @@ static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list) kfree(*list); } - +/* create/free virtual FE dai links */ +int soc_dpcm_vfe_new(struct snd_soc_card *, int index, const char *link_name, + const char *cpu_dai_name, const char *platform_name); +int soc_dpcm_vfe_free(struct snd_soc_card *card); #endif diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4ce489165a6d9b..42788dc2a292e3 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1582,7 +1582,6 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, /* Create any new FE <--> BE connections */ for (i = 0; i < list->num_widgets; i++) { - switch (list->widgets[i]->id) { case snd_soc_dapm_dai_in: if (stream != SNDRV_PCM_STREAM_PLAYBACK) @@ -2789,6 +2788,114 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) return 0; } +/* + * create a virtual FE DAI link + * Virtual FE DAI links are used in hostless pipelines + * to enable the codecs when the pipeline is triggered + */ +int soc_dpcm_vfe_new(struct snd_soc_card *card, int index, + const char *link_name, const char *cpu_dai_name, + const char *platform_name) +{ + struct snd_soc_dai_link *link; + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return -ENOMEM; + + dev_dbg(card->dev, "ASoC: adding new virtual FE DAI link %s\n", + link_name); + + /* define virtual FE DAI link */ + link->virtual = 1; + link->name = link_name; + link->id = 1; + link->cpu_dai_name = cpu_dai_name; + link->platform_name = platform_name; + link->codec_name = "snd-soc-dummy"; + link->codec_dai_name = "snd-soc-dummy-dai"; + link->num_codecs = 1; + + /* allocate memory for link codecs */ + link->codecs = devm_kzalloc(card->dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!link->codecs) + return -ENOMEM; + + link->codecs[0].name = link->codec_name; + link->codecs[0].dai_name = link->codec_dai_name; + + /* enable DPCM */ + link->dynamic = 1; + + /*TODO: check if we need to handle capture for virtual FE */ + link->dpcm_playback = 1; + + link->dobj.index = index; + link->dobj.type = SND_SOC_DOBJ_DAI_LINK; + + /* add virtual dai link to card dai link list */ + snd_soc_add_dai_link(card, link); + + return 0; +} +EXPORT_SYMBOL_GPL(soc_dpcm_vfe_new); + +/* free virtual FE DAI link */ +int soc_dpcm_vfe_free(struct snd_soc_card *card) +{ + struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2; + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm_str *pstr; + int stream_dir; + + list_for_each_entry(rtd, &card->rtd_list, list) { + + /* check if this is a virtual dai link */ + if (rtd->dai_link->virtual) { + + if (rtd->dai_link->dpcm_playback) { + stream_dir = SNDRV_PCM_STREAM_PLAYBACK; + + /* disconnect FE from BE */ + dpcm_be_disconnect(rtd, stream_dir); + + /* free pcm runtime */ + kfree(rtd->dpcm[stream_dir].runtime); + + pstr = &rtd->pcm->streams[stream_dir]; + + /* free pcm substream amd pcm */ + kfree(pstr->substream); + } + + /* free pcm */ + kfree(rtd->pcm); + + /* free codec dais and component list */ + kfree(rtd->codec_dais); + + for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2) + kfree(rtdcom1); + + INIT_LIST_HEAD(&rtd->component_list); + + /* remove dai_link from card */ + snd_soc_remove_dai_link(card, rtd->dai_link); + + /* free link */ + kfree(rtd->dai_link); + + /* free runtime */ + kfree(rtd); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(soc_dpcm_vfe_free); + static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) { struct snd_soc_pcm_runtime *fe = fe_substream->private_data; From 61943861567c9ab54ee0eae3b215baab896b0a0b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 22 Jun 2018 21:15:04 -0700 Subject: [PATCH 3/6] ASoC: dapm: dont delete starting point if list is singular When walking the graph to discover the path from the virtual FE to the BE, there is only one widget in the path. Do not remove this BE widget from the list, so it can be used to connect with the virtual FE dai link. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-dapm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6d54128e44b46b..08e38883d43299 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1246,7 +1246,8 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, custom_stop_condition); /* Drop starting point */ - list_del(widgets.next); + if (!list_is_singular(&widgets)) + list_del(widgets.next); ret = dapm_widget_list_create(list, &widgets); if (ret) From e0a94e9d6e26e056da06313910438d6b117f0145 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 22 Jun 2018 21:27:16 -0700 Subject: [PATCH 4/6] ASoC: core: set runtime and the cpu_dai/codec_dai active status for virtual dai link Virtual FE dai links should be manually set to running state by default with a pcm runtime. The active count of their cpu_dai and codec_dai's should also be updated. This is required to establish FE-BE connection and enable the BE DAI when the dpcm runtime is updated. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-core.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a0160a409e4094..4a9bdcde3aa036 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1047,6 +1047,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; struct device_node *platform_of_node; + struct snd_pcm_runtime *runtime; const char *platform_name; int i; @@ -1134,6 +1135,25 @@ static int soc_bind_dai_link(struct snd_soc_card *card, } soc_add_pcm_runtime(card, rtd); + + /* if the dai link is virtual, create runtime to set it as running */ + if (rtd->dai_link->virtual) { + runtime = kzalloc(sizeof(*runtime), + GFP_KERNEL); + if (!runtime) + return -ENOMEM; + + if (rtd->dai_link->dpcm_playback) { + rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].runtime = runtime; + rtd->cpu_dai->playback_active = 1; + rtd->codec_dai->playback_active = 1; + } + + /* increment the active count for cpu dai */ + rtd->cpu_dai->active++; + + /* does virtual FE for capture make sense */ + } return 0; _err_defer: From 481f66db806cc5e50714c85b3939a984ff3f466c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 23 Jun 2018 20:48:41 -0700 Subject: [PATCH 5/6] ASoC: pcm: do no register pcm device for virtual FE dai links Virtual FE dai links do not need to register the pcm device. So just create the empty pcm device and substream in the requested direction. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-pcm.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 42788dc2a292e3..64f459030f1c68 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3111,7 +3111,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; + struct snd_pcm_substream *substream; struct snd_pcm *pcm; + int stream_dir; char new_name[64]; int ret = 0, playback = 0, capture = 0; int i; @@ -3150,6 +3152,44 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, playback, capture, &pcm); } else { + + /* + * for virtual FE dai links, there is no need + * to register PCM device. So only allocate memory for + * pcm device and substream for the requested direction + */ + if (rtd->dai_link->virtual) { + struct snd_pcm_str *pstr; + + if (rtd->dai_link->dpcm_playback) + stream_dir = SNDRV_PCM_STREAM_PLAYBACK; + + pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pstr = &pcm->streams[stream_dir]; + + substream = kzalloc(sizeof(*substream), GFP_KERNEL); + if (!substream) + return -ENOMEM; + + substream->pcm = pcm; + substream->pstr = pstr; + substream->number = 0; + substream->stream = stream_dir; + sprintf(substream->name, "subdevice #%i", 0); + substream->buffer_bytes_max = UINT_MAX; + + pstr->substream = substream; + + pcm->nonatomic = rtd->dai_link->nonatomic; + rtd->pcm = pcm; + pcm->private_data = rtd; + + goto out; + } + if (rtd->dai_link->dynamic) snprintf(new_name, sizeof(new_name), "%s (*)", rtd->dai_link->stream_name); From 862fd6d2612246af1c4aac5a94c48da5201b35ae Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 23 Jun 2018 21:46:34 -0700 Subject: [PATCH 6/6] ASoC: pcm: make soc_dpcm_runtime_update() accessible from modules the soc_dpcm_runtime_update() method will be called to establish a connection to the BE and enable the codec. So make this method accessible to modules. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 64f459030f1c68..40a3f34ef2d66d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2758,6 +2758,8 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) mutex_unlock(&card->mutex); return 0; } +EXPORT_SYMBOL_GPL(soc_dpcm_runtime_update); + int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) { struct snd_soc_dpcm *dpcm;