topology: add snd_tplg_save()

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2019-12-16 14:26:31 +01:00
parent 4a0efdc873
commit aa1bac2d04
14 changed files with 2165 additions and 260 deletions

View file

@ -28,15 +28,16 @@ struct ctl_access_elem {
};
/* CTL access strings and codes */
/* place the multi-bit values on top - like read_write - for save */
static const struct ctl_access_elem ctl_access[] = {
{"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE},
{"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE},
{"read", SNDRV_CTL_ELEM_ACCESS_READ},
{"write", SNDRV_CTL_ELEM_ACCESS_WRITE},
{"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE},
{"volatile", SNDRV_CTL_ELEM_ACCESS_VOLATILE},
{"timestamp", SNDRV_CTL_ELEM_ACCESS_TIMESTAMP},
{"tlv_read", SNDRV_CTL_ELEM_ACCESS_TLV_READ},
{"tlv_write", SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
{"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE},
{"tlv_command", SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
{"inactive", SNDRV_CTL_ELEM_ACCESS_INACTIVE},
{"lock", SNDRV_CTL_ELEM_ACCESS_LOCK},
@ -103,6 +104,46 @@ int parse_access(snd_config_t *cfg,
return err;
}
/* Save Access */
static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
struct snd_soc_tplg_ctl_hdr *hdr, char **dst,
const char *pfx)
{
const char *last;
unsigned int j, count, access, cval;
int err;
if (hdr->access == 0)
return 0;
access = hdr->access;
for (j = 0, count = 0, last = NULL; j < ARRAY_SIZE(ctl_access); j++) {
cval = ctl_access[j].value;
if ((access & cval) == cval) {
access &= ~cval;
last = ctl_access[j].name;
count++;
}
}
if (count == 1)
return tplg_save_printf(dst, pfx, "access.0 %s\n", last);
err = tplg_save_printf(dst, pfx, "access [\n");
if (err < 0)
return err;
access = hdr->access;
for (j = 0; j < ARRAY_SIZE(ctl_access); j++) {
cval = ctl_access[j].value;
if ((access & cval) == cval) {
err = tplg_save_printf(dst, pfx, "\t%s\n",
ctl_access[j].name);
if (err < 0)
return err;
access &= ~cval;
}
}
return tplg_save_printf(dst, pfx, "]\n");
}
/* copy referenced TLV to the mixer control */
static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
{
@ -358,6 +399,37 @@ int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
return err;
}
/* save TLV data */
int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
struct tplg_elem *elem,
char **dst, const char *pfx)
{
struct snd_soc_tplg_ctl_tlv *tlv = elem->tlv;
struct snd_soc_tplg_tlv_dbscale *scale;
int err;
if (tlv->type != SNDRV_CTL_TLVT_DB_SCALE) {
SNDERR("unknown TLV type");
return -EINVAL;
}
scale = &tlv->scale;
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
if (err >= 0)
err = tplg_save_printf(dst, pfx, "\tscale {\n");
if (err >= 0 && scale->min)
err = tplg_save_printf(dst, pfx, "\t\tmin %i\n", scale->min);
if (err >= 0 && scale->step > 0)
err = tplg_save_printf(dst, pfx, "\t\tstep %i\n", scale->step);
if (err >= 0 && scale->mute > 0)
err = tplg_save_printf(dst, pfx, "\t\tmute %i\n", scale->mute);
if (err >= 0)
err = tplg_save_printf(dst, pfx, "\t}\n");
if (err >= 0)
err = tplg_save_printf(dst, pfx, "}\n");
return err;
}
/* Parse Control Bytes */
int tplg_parse_control_bytes(snd_tplg_t *tplg,
snd_config_t *cfg,
@ -430,7 +502,7 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg,
}
if (strcmp(id, "data") == 0) {
err = tplg_parse_data_refs(n, elem);
err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
if (err < 0)
return err;
continue;
@ -485,6 +557,49 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg,
return 0;
}
/* save control bytes */
int tplg_save_control_bytes(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
struct tplg_elem *elem,
char **dst, const char *pfx)
{
struct snd_soc_tplg_bytes_control *be = elem->bytes_ext;
char pfx2[16];
int err;
if (!be)
return 0;
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
if (err < 0)
return err;
if (err >= 0 && elem->index > 0)
err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
if (err >= 0 && be->base > 0)
err = tplg_save_printf(dst, pfx, "\tbase %u\n", be->base);
if (err >= 0 && be->num_regs > 0)
err = tplg_save_printf(dst, pfx, "\tnum_regs %u\n", be->num_regs);
if (err >= 0 && be->max > 0)
err = tplg_save_printf(dst, pfx, "\tmax %u\n", be->max);
if (err >= 0 && be->mask > 0)
err = tplg_save_printf(dst, pfx, "\tmask %u\n", be->mask);
if (err >= 0)
err = tplg_save_ops(tplg, &be->hdr, dst, pfx2);
if (err >= 0)
err = tplg_save_ext_ops(tplg, be, dst, pfx2);
if (err >= 0)
err = tplg_save_access(tplg, &be->hdr, dst, pfx2);
if (err >= 0)
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
"tlv", dst, pfx2);
if (err >= 0)
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
"data", dst, pfx2);
if (err >= 0)
err = tplg_save_printf(dst, pfx, "}\n");
return err;
}
/* Parse Control Enums. */
int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
void *private ATTRIBUTE_UNUSED)
@ -559,7 +674,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
}
if (strcmp(id, "data") == 0) {
err = tplg_parse_data_refs(n, elem);
err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
if (err < 0)
return err;
continue;
@ -582,6 +697,42 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
return 0;
}
/* save control eunm */
int tplg_save_control_enum(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
struct tplg_elem *elem,
char **dst, const char *pfx)
{
struct snd_soc_tplg_enum_control *ec = elem->enum_ctrl;
char pfx2[16];
int err;
if (!ec)
return 0;
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
if (err < 0)
return err;
if (err >= 0 && elem->index > 0)
err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
if (err >= 0)
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TEXT,
"texts", dst, pfx2);
if (err >= 0)
err = tplg_save_channels(tplg, ec->channel, ec->num_channels,
dst, pfx2);
if (err >= 0)
err = tplg_save_ops(tplg, &ec->hdr, dst, pfx2);
if (err >= 0)
err = tplg_save_access(tplg, &ec->hdr, dst, pfx2);
if (err >= 0)
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
"data", dst, pfx2);
if (err >= 0)
err = tplg_save_printf(dst, pfx, "}\n");
return err;
}
/* Parse Controls.
*
* Mixer control. Supports multiple channels.
@ -683,7 +834,7 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg,
}
if (strcmp(id, "data") == 0) {
err = tplg_parse_data_refs(n, elem);
err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
if (err < 0)
return err;
continue;
@ -709,6 +860,46 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg,
return 0;
}
int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
struct tplg_elem *elem, char **dst,
const char *pfx)
{
struct snd_soc_tplg_mixer_control *mc = elem->mixer_ctrl;
char pfx2[16];
int err;
if (!mc)
return 0;
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
if (err < 0)
return err;
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
if (err >= 0 && elem->index > 0)
err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
if (err >= 0)
err = tplg_save_channels(tplg, mc->channel, mc->num_channels,
dst, pfx2);
if (err >= 0 && mc->max > 0)
err = tplg_save_printf(dst, pfx, "\tmax %u\n", mc->max);
if (err >= 0 && mc->invert > 0)
err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max);
if (err >= 0 && mc->invert > 0)
err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max);
if (err >= 0)
err = tplg_save_ops(tplg, &mc->hdr, dst, pfx2);
if (err >= 0)
err = tplg_save_access(tplg, &mc->hdr, dst, pfx2);
if (err >= 0)
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
"tlv", dst, pfx2);
if (err >= 0)
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
"data", dst, pfx2);
if (err >= 0)
err = tplg_save_printf(dst, pfx, "}\n");
return err;
}
static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
struct snd_tplg_ctl_template *t)
{