topology: ABI - Separate PCM & BE/CC link support and bump ABI version to 4

The struct snd_soc_tplg_pcm_dai is renamed to snd_soc_tplg_pcm.
This struct will now be used to handle data related to PCMs
(FE DAI & DAI links). It's not for BE, because BE DAI mappings will be
provided by ACPI/FDT data.

Remove the unused struct snd_soc_tplg_pcm_cfg_caps. We are using
snd_soc_tplg_stream and snd_soc_stream_caps instead.

Define the topology type for BE DAI link: SND_SOC_TPLG_TYPE_BACKEND_LINK.

Define struct snd_soc_tplg_link_config to configure BE & CC links.

Bump ABI version to 4.

Signed-off-by: Vedang Patel <vedang.patel@intel.com>
Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Vedang Patel 2015-11-05 20:48:30 +08:00 committed by Jaroslav Kysela
parent b73d50fc2b
commit 368e4f2a89
5 changed files with 134 additions and 287 deletions

View file

@ -23,7 +23,7 @@ struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
{
struct list_head *pos;
struct tplg_elem *elem;
struct snd_soc_tplg_pcm_dai *pcm_dai;
struct snd_soc_tplg_pcm *pcm;
list_for_each(pos, base) {
@ -31,10 +31,9 @@ struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
if (elem->type != SND_TPLG_TYPE_PCM)
return NULL;
pcm_dai = elem->pcm;
pcm = elem->pcm;
if (pcm_dai && (!strcmp(pcm_dai->capconf[0].caps.name, id)
|| !strcmp(pcm_dai->capconf[1].caps.name, id)))
if (pcm && !strcmp(pcm->dai_name, id))
return elem;
}
@ -53,74 +52,82 @@ static void copy_pcm_caps(const char *id, struct snd_soc_tplg_stream_caps *caps,
*caps = *ref_caps;
}
/* copy referenced config to the pcm */
static void copy_pcm_config(const char *id,
struct snd_soc_tplg_stream_config *cfg, struct tplg_elem *ref_elem)
{
struct snd_soc_tplg_stream_config *ref_cfg = ref_elem->stream_cfg;
tplg_dbg("Copy pcm config (%ld bytes) from '%s' to '%s' \n",
sizeof(*cfg), ref_elem->id, id);
*cfg = *ref_cfg;
}
/* check referenced config and caps for a pcm */
static int tplg_build_pcm_cfg_caps(snd_tplg_t *tplg, struct tplg_elem *elem)
static int tplg_build_pcm_caps(snd_tplg_t *tplg, struct tplg_elem *elem)
{
struct tplg_elem *ref_elem = NULL;
struct snd_soc_tplg_pcm_cfg_caps *capconf;
struct snd_soc_tplg_pcm_dai *pcm_dai;
unsigned int i, j;
struct snd_soc_tplg_pcm *pcm;
struct snd_soc_tplg_stream_caps *caps;
struct snd_soc_tplg_stream *stream;
unsigned int i;
switch (elem->type) {
case SND_TPLG_TYPE_PCM:
pcm_dai = elem->pcm;
break;
case SND_TPLG_TYPE_BE:
pcm_dai = elem->be;
break;
case SND_TPLG_TYPE_CC:
pcm_dai = elem->cc;
break;
default:
return -EINVAL;
}
pcm = elem->pcm;
for (i = 0; i < 2; i++) {
capconf = &pcm_dai->capconf[i];
caps = &pcm->caps[i];
ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
capconf->caps.name, SND_TPLG_TYPE_STREAM_CAPS);
caps->name, SND_TPLG_TYPE_STREAM_CAPS);
if (ref_elem != NULL)
copy_pcm_caps(elem->id, &capconf->caps, ref_elem);
for (j = 0; j < capconf->num_configs; j++) {
ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
capconf->configs[j].name,
SND_TPLG_TYPE_STREAM_CONFIG);
if (ref_elem != NULL)
copy_pcm_config(elem->id,
&capconf->configs[j],
ref_elem);
}
copy_pcm_caps(elem->id, caps, ref_elem);
}
return 0;
}
int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type)
/* build FE DAI/PCM configurations */
int tplg_build_pcm(snd_tplg_t *tplg, unsigned int type)
{
struct list_head *base, *pos;
struct tplg_elem *elem;
int err = 0;
base = &tplg->pcm_list;
list_for_each(pos, base) {
elem = list_entry(pos, struct tplg_elem, list);
if (elem->type != type) {
SNDERR("error: invalid elem '%s'\n", elem->id);
return -EINVAL;
}
err = tplg_build_pcm_caps(tplg, elem);
if (err < 0)
return err;
}
return 0;
}
static int tplg_build_stream_cfg(snd_tplg_t *tplg,
struct snd_soc_tplg_stream *stream, int num_streams)
{
struct snd_soc_tplg_stream *strm;
struct tplg_elem *ref_elem;
int i;
for (i = 0; i < num_streams; i++) {
strm = stream + i;
ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
strm->name, SND_TPLG_TYPE_STREAM_CONFIG);
if (ref_elem && ref_elem->stream_cfg)
*strm = *ref_elem->stream_cfg;
}
return 0;
}
/* build BE/CC DAI link configurations */
int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type)
{
struct list_head *base, *pos;
struct tplg_elem *elem;
struct snd_soc_tplg_link_config *link;
int err = 0;
switch (type) {
case SND_TPLG_TYPE_PCM:
base = &tplg->pcm_list;
break;
case SND_TPLG_TYPE_BE:
base = &tplg->be_list;
break;
@ -139,7 +146,13 @@ int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type)
return -EINVAL;
}
err = tplg_build_pcm_cfg_caps(tplg, elem);
if (type == SND_TPLG_TYPE_BE)
link = elem->be;
else
link = elem->cc;
err = tplg_build_stream_cfg(tplg, link->stream,
link->num_streams);
if (err < 0)
return err;
}
@ -147,118 +160,6 @@ int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type)
return 0;
}
/* PCM stream configuration */
static int tplg_parse_stream_cfg(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
snd_config_t *cfg, void *private)
{
snd_config_iterator_t i, next;
snd_config_t *n;
struct snd_soc_tplg_stream_config *sc = private;
struct snd_soc_tplg_stream *stream;
const char *id, *val;
snd_pcm_format_t format;
snd_config_get_id(cfg, &id);
if (strcmp(id, "playback") == 0)
stream = &sc->playback;
else if (strcmp(id, "capture") == 0)
stream = &sc->capture;
else
return -EINVAL;
tplg_dbg("\t%s:\n", id);
stream->size = sizeof(*stream);
snd_config_for_each(i, next, cfg) {
n = snd_config_iterator_entry(i);
if (snd_config_get_id(n, &id) < 0)
return -EINVAL;
if (snd_config_get_string(n, &val) < 0)
return -EINVAL;
if (strcmp(id, "format") == 0) {
format = snd_pcm_format_value(val);
if (format == SND_PCM_FORMAT_UNKNOWN) {
SNDERR("error: unsupported stream format %s\n",
val);
return -EINVAL;
}
stream->format = format;
tplg_dbg("\t\t%s: %s\n", id, val);
continue;
}
if (strcmp(id, "rate") == 0) {
stream->rate = atoi(val);
tplg_dbg("\t\t%s: %d\n", id, stream->rate);
continue;
}
if (strcmp(id, "channels") == 0) {
stream->channels = atoi(val);
tplg_dbg("\t\t%s: %d\n", id, stream->channels);
continue;
}
if (strcmp(id, "tdm_slot") == 0) {
stream->tdm_slot = strtol(val, NULL, 16);
tplg_dbg("\t\t%s: 0x%x\n", id, stream->tdm_slot);
continue;
}
}
return 0;
}
/* Parse pcm configuration */
int tplg_parse_pcm_config(snd_tplg_t *tplg,
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
{
struct snd_soc_tplg_stream_config *sc;
struct tplg_elem *elem;
snd_config_iterator_t i, next;
snd_config_t *n;
const char *id;
int err;
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CONFIG);
if (!elem)
return -ENOMEM;
sc = elem->stream_cfg;
sc->size = elem->size;
tplg_dbg(" PCM Config: %s\n", elem->id);
snd_config_for_each(i, next, cfg) {
n = snd_config_iterator_entry(i);
if (snd_config_get_id(n, &id) < 0)
continue;
/* skip comments */
if (strcmp(id, "comment") == 0)
continue;
if (id[0] == '#')
continue;
if (strcmp(id, "config") == 0) {
err = tplg_parse_compound(tplg, n,
tplg_parse_stream_cfg, sc);
if (err < 0)
return err;
continue;
}
}
return 0;
}
static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
{
char *s = NULL;
@ -360,49 +261,18 @@ int tplg_parse_pcm_caps(snd_tplg_t *tplg,
return 0;
}
static int tplg_parse_pcm_cfg(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
snd_config_t *cfg, void *private)
{
struct snd_soc_tplg_pcm_cfg_caps *capconf = private;
struct snd_soc_tplg_stream_config *configs = capconf->configs;
unsigned int *num_configs = &capconf->num_configs;
const char *value;
if (*num_configs == SND_SOC_TPLG_STREAM_CONFIG_MAX)
return -EINVAL;
if (snd_config_get_string(cfg, &value) < 0)
return EINVAL;
elem_copy_text(configs[*num_configs].name, value,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
*num_configs += 1;
tplg_dbg("\t\t\t%s\n", value);
return 0;
}
/* Parse the cap and config of a pcm */
int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
/* Parse the caps of a pcm stream */
int tplg_parse_stream_caps(snd_tplg_t *tplg, snd_config_t *cfg,
void *private)
{
snd_config_iterator_t i, next;
snd_config_t *n;
struct tplg_elem *elem = private;
struct snd_soc_tplg_pcm_dai *pcm_dai;
struct snd_soc_tplg_pcm *pcm;
const char *id, *value;
int err, stream;
if (elem->type == SND_TPLG_TYPE_PCM)
pcm_dai = elem->pcm;
else if (elem->type == SND_TPLG_TYPE_BE)
pcm_dai = elem->be;
else if (elem->type == SND_TPLG_TYPE_CC)
pcm_dai = elem->cc;
else
return -EINVAL;
pcm = elem->pcm;
snd_config_get_id(cfg, &id);
@ -410,10 +280,10 @@ int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
if (strcmp(id, "playback") == 0) {
stream = SND_SOC_TPLG_STREAM_PLAYBACK;
pcm_dai->playback = 1;
pcm->playback = 1;
} else if (strcmp(id, "capture") == 0) {
stream = SND_SOC_TPLG_STREAM_CAPTURE;
pcm_dai->capture = 1;
pcm->capture = 1;
} else
return -EINVAL;
@ -429,21 +299,12 @@ int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
if (snd_config_get_string(n, &value) < 0)
continue;
elem_copy_text(pcm_dai->capconf[stream].caps.name, value,
elem_copy_text(pcm->caps[stream].name, value,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
tplg_dbg("\t\t%s\n\t\t\t%s\n", id, value);
continue;
}
if (strcmp(id, "configs") == 0) {
tplg_dbg("\t\tconfigs:\n");
err = tplg_parse_compound(tplg, n, tplg_parse_pcm_cfg,
&pcm_dai->capconf[stream]);
if (err < 0)
return err;
continue;
}
}
return 0;
@ -453,7 +314,7 @@ int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
int tplg_parse_pcm(snd_tplg_t *tplg,
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
{
struct snd_soc_tplg_pcm_dai *pcm_dai;
struct snd_soc_tplg_pcm *pcm;
struct tplg_elem *elem;
snd_config_iterator_t i, next;
snd_config_t *n;
@ -464,9 +325,9 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
if (!elem)
return -ENOMEM;
pcm_dai = elem->pcm;
pcm_dai->size = elem->size;
elem_copy_text(pcm_dai->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
pcm = elem->pcm;
pcm->size = elem->size;
elem_copy_text(pcm->dai_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
tplg_dbg(" PCM: %s\n", elem->id);
@ -495,14 +356,14 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
if (snd_config_get_string(n, &val) < 0)
return -EINVAL;
pcm_dai->id = atoi(val);
tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
pcm->dai_id = atoi(val);
tplg_dbg("\t%s: %d\n", id, pcm->dai_id);
continue;
}
if (strcmp(id, "pcm") == 0) {
err = tplg_parse_compound(tplg, n,
tplg_parse_pcm_cap_cfg, elem);
tplg_parse_stream_caps, elem);
if (err < 0)
return err;
continue;
@ -512,11 +373,10 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
return 0;
}
/* Parse be */
int tplg_parse_be(snd_tplg_t *tplg,
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
{
struct snd_soc_tplg_pcm_dai *pcm_dai;
struct snd_soc_tplg_link_config *link;
struct tplg_elem *elem;
snd_config_iterator_t i, next;
snd_config_t *n;
@ -527,9 +387,8 @@ int tplg_parse_be(snd_tplg_t *tplg,
if (!elem)
return -ENOMEM;
pcm_dai = elem->be;
pcm_dai->size = elem->size;
elem_copy_text(pcm_dai->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
link = elem->be;
link->size = elem->size;
tplg_dbg(" BE: %s\n", elem->id);
@ -558,16 +417,8 @@ int tplg_parse_be(snd_tplg_t *tplg,
if (snd_config_get_string(n, &val) < 0)
return -EINVAL;
pcm_dai->id = atoi(val);
tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
continue;
}
if (strcmp(id, "be") == 0) {
err = tplg_parse_compound(tplg, n,
tplg_parse_pcm_cap_cfg, elem);
if (err < 0)
return err;
link->id = atoi(val);
tplg_dbg("\t%s: %d\n", id, link->id);
continue;
}
}
@ -579,7 +430,7 @@ int tplg_parse_be(snd_tplg_t *tplg,
int tplg_parse_cc(snd_tplg_t *tplg,
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
{
struct snd_soc_tplg_pcm_dai *pcm_dai;
struct snd_soc_tplg_link_config *link;
struct tplg_elem *elem;
snd_config_iterator_t i, next;
snd_config_t *n;
@ -590,8 +441,8 @@ int tplg_parse_cc(snd_tplg_t *tplg,
if (!elem)
return -ENOMEM;
pcm_dai = elem->cc;
pcm_dai->size = elem->size;
link = elem->cc;
link->size = elem->size;
tplg_dbg(" CC: %s\n", elem->id);
@ -620,18 +471,11 @@ int tplg_parse_cc(snd_tplg_t *tplg,
if (snd_config_get_string(n, &val) < 0)
return -EINVAL;
pcm_dai->id = atoi(val);
tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
link->id = atoi(val);
tplg_dbg("\t%s: %d\n", id, link->id);
continue;
}
if (strcmp(id, "cc") == 0) {
err = tplg_parse_compound(tplg, n,
tplg_parse_pcm_cap_cfg, elem);
if (err < 0)
return err;
continue;
}
}
return 0;