Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing Virtual FE dai link #6

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion include/sound/soc-dpcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 11 additions & 0 deletions include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};
Expand Down
20 changes: 20 additions & 0 deletions sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion sound/soc/soc-dapm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
151 changes: 150 additions & 1 deletion sound/soc/soc-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -2759,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;
Expand Down Expand Up @@ -2789,6 +2790,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;
Expand Down Expand Up @@ -3004,7 +3113,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;
Expand Down Expand Up @@ -3043,6 +3154,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);
Expand Down