|
Packit |
4a16fb |
/*
|
|
Packit |
4a16fb |
Copyright(c) 2014-2015 Intel Corporation
|
|
Packit |
4a16fb |
All rights reserved.
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
This library is free software; you can redistribute it and/or modify
|
|
Packit |
4a16fb |
it under the terms of the GNU Lesser General Public License as
|
|
Packit |
4a16fb |
published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
4a16fb |
the License, or (at your option) any later version.
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
This program is distributed in the hope that it will be useful,
|
|
Packit |
4a16fb |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4a16fb |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
4a16fb |
GNU Lesser General Public License for more details.
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
Authors: Mengdong Lin <mengdong.lin@intel.com>
|
|
Packit |
4a16fb |
Yao Jin <yao.jin@intel.com>
|
|
Packit |
4a16fb |
Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#include "list.h"
|
|
Packit |
4a16fb |
#include "tplg_local.h"
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#define RATE(v) [SND_PCM_RATE_##v] = #v
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static const char *const snd_pcm_rate_names[] = {
|
|
Packit |
4a16fb |
RATE(5512),
|
|
Packit |
4a16fb |
RATE(8000),
|
|
Packit |
4a16fb |
RATE(11025),
|
|
Packit |
4a16fb |
RATE(16000),
|
|
Packit |
4a16fb |
RATE(22050),
|
|
Packit |
4a16fb |
RATE(32000),
|
|
Packit |
4a16fb |
RATE(44100),
|
|
Packit |
4a16fb |
RATE(48000),
|
|
Packit |
4a16fb |
RATE(64000),
|
|
Packit |
4a16fb |
RATE(88200),
|
|
Packit |
4a16fb |
RATE(96000),
|
|
Packit |
4a16fb |
RATE(176400),
|
|
Packit |
4a16fb |
RATE(192000),
|
|
Packit |
4a16fb |
RATE(CONTINUOUS),
|
|
Packit |
4a16fb |
RATE(KNOT),
|
|
Packit |
4a16fb |
};
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *pos;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
struct snd_soc_tplg_pcm *pcm;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = list_entry(pos, struct tplg_elem, list);
|
|
Packit |
4a16fb |
if (elem->type != SND_TPLG_TYPE_PCM)
|
|
Packit |
4a16fb |
return NULL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
pcm = elem->pcm;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (pcm && !strcmp(pcm->dai_name, id))
|
|
Packit |
4a16fb |
return elem;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return NULL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* copy referenced caps to the parent (pcm or be dai) */
|
|
Packit |
4a16fb |
static void copy_stream_caps(const char *id ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_stream_caps *caps,
|
|
Packit Service |
f36a15 |
struct tplg_elem *ref_elem)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("Copy pcm caps (%ld bytes) from '%s' to '%s'",
|
|
Packit |
4a16fb |
sizeof(*caps), ref_elem->id, id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
*caps = *ref_caps;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* find and copy the referenced stream caps */
|
|
Packit |
4a16fb |
static int tplg_build_stream_caps(snd_tplg_t *tplg,
|
|
Packit Service |
f36a15 |
const char *id, int index,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_stream_caps *caps)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct tplg_elem *ref_elem = NULL;
|
|
Packit |
4a16fb |
unsigned int i;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (i = 0; i < 2; i++) {
|
|
Packit |
4a16fb |
ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
|
|
Packit |
4a16fb |
caps[i].name, SND_TPLG_TYPE_STREAM_CAPS, index);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (ref_elem != NULL)
|
|
Packit |
4a16fb |
copy_stream_caps(id, &caps[i], ref_elem);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* build a PCM (FE DAI & DAI link) element */
|
|
Packit |
4a16fb |
static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct tplg_ref *ref;
|
|
Packit |
4a16fb |
struct list_head *base, *pos;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = tplg_build_stream_caps(tplg, elem->id, elem->index,
|
|
Packit |
4a16fb |
elem->pcm->caps);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* merge private data from the referenced data elements */
|
|
Packit |
4a16fb |
base = &elem->ref_list;
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
ref = list_entry(pos, struct tplg_ref, list);
|
|
Packit |
4a16fb |
if (ref->type == SND_TPLG_TYPE_DATA) {
|
|
Packit |
4a16fb |
err = tplg_copy_data(tplg, elem, ref);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (!ref->elem) {
|
|
Packit Service |
f36a15 |
SNDERR("cannot find '%s' referenced by"
|
|
Packit Service |
f36a15 |
" PCM '%s'", ref->id, elem->id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* build all PCM (FE DAI & DAI link) elements */
|
|
Packit |
4a16fb |
int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *base, *pos;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
int err = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
base = &tplg->pcm_list;
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = list_entry(pos, struct tplg_elem, list);
|
|
Packit |
4a16fb |
if (elem->type != type) {
|
|
Packit Service |
f36a15 |
SNDERR("invalid elem '%s'", elem->id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = build_pcm(tplg, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* add PCM to manifest */
|
|
Packit |
4a16fb |
tplg->manifest.pcm_elems++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* build a physical DAI */
|
|
Packit |
4a16fb |
static int tplg_build_dai(snd_tplg_t *tplg, struct tplg_elem *elem)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct tplg_ref *ref;
|
|
Packit |
4a16fb |
struct list_head *base, *pos;
|
|
Packit |
4a16fb |
int err = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* get playback & capture stream caps */
|
|
Packit |
4a16fb |
err = tplg_build_stream_caps(tplg, elem->id, elem->index,
|
|
Packit |
4a16fb |
elem->dai->caps);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* get private data */
|
|
Packit |
4a16fb |
base = &elem->ref_list;
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
ref = list_entry(pos, struct tplg_ref, list);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (ref->type == SND_TPLG_TYPE_DATA) {
|
|
Packit |
4a16fb |
err = tplg_copy_data(tplg, elem, ref);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* add DAI to manifest */
|
|
Packit |
4a16fb |
tplg->manifest.dai_elems++;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* build physical DAIs*/
|
|
Packit |
4a16fb |
int tplg_build_dais(snd_tplg_t *tplg, unsigned int type)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *base, *pos;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
int err = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
base = &tplg->dai_list;
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = list_entry(pos, struct tplg_elem, list);
|
|
Packit |
4a16fb |
if (elem->type != type) {
|
|
Packit Service |
f36a15 |
SNDERR("invalid elem '%s'", elem->id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = tplg_build_dai(tplg, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int tplg_build_stream_cfg(snd_tplg_t *tplg,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_stream *stream,
|
|
Packit Service |
f36a15 |
int num_streams, int index)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_stream *strm;
|
|
Packit |
4a16fb |
struct tplg_elem *ref_elem;
|
|
Packit |
4a16fb |
int i;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (i = 0; i < num_streams; i++) {
|
|
Packit |
4a16fb |
strm = stream + i;
|
|
Packit |
4a16fb |
ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
|
|
Packit |
4a16fb |
strm->name, SND_TPLG_TYPE_STREAM_CONFIG, index);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (ref_elem && ref_elem->stream_cfg)
|
|
Packit |
4a16fb |
*strm = *ref_elem->stream_cfg;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_link_config *link = elem->link;
|
|
Packit |
4a16fb |
struct tplg_ref *ref;
|
|
Packit |
4a16fb |
struct list_head *base, *pos;
|
|
Packit |
4a16fb |
int num_hw_configs = 0, err = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = tplg_build_stream_cfg(tplg, link->stream,
|
|
Packit |
4a16fb |
link->num_streams, elem->index);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* hw configs & private data */
|
|
Packit |
4a16fb |
base = &elem->ref_list;
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
ref = list_entry(pos, struct tplg_ref, list);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
switch (ref->type) {
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_HW_CONFIG:
|
|
Packit |
4a16fb |
ref->elem = tplg_elem_lookup(&tplg->hw_cfg_list,
|
|
Packit |
4a16fb |
ref->id, SND_TPLG_TYPE_HW_CONFIG, elem->index);
|
|
Packit |
4a16fb |
if (!ref->elem) {
|
|
Packit Service |
f36a15 |
SNDERR("cannot find HW config '%s'"
|
|
Packit Service |
f36a15 |
" referenced by link '%s'",
|
|
Packit Service |
f36a15 |
ref->id, elem->id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
memcpy(&link->hw_config[num_hw_configs],
|
|
Packit |
4a16fb |
ref->elem->hw_cfg,
|
|
Packit |
4a16fb |
sizeof(struct snd_soc_tplg_hw_config));
|
|
Packit |
4a16fb |
num_hw_configs++;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_DATA: /* merge private data */
|
|
Packit |
4a16fb |
err = tplg_copy_data(tplg, elem, ref);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit Service |
f36a15 |
link = elem->link; /* realloc */
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
default:
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* add link to manifest */
|
|
Packit |
4a16fb |
tplg->manifest.dai_link_elems++;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* build physical DAI link configurations */
|
|
Packit |
4a16fb |
int tplg_build_links(snd_tplg_t *tplg, unsigned int type)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *base, *pos;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
int err = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
switch (type) {
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_LINK:
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_BE:
|
|
Packit |
4a16fb |
base = &tplg->be_list;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_CC:
|
|
Packit |
4a16fb |
base = &tplg->cc_list;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
default:
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
list_for_each(pos, base) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = list_entry(pos, struct tplg_elem, list);
|
|
Packit |
4a16fb |
err = build_link(tplg, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
char *s = NULL;
|
|
Packit |
4a16fb |
snd_pcm_format_t format;
|
|
Packit |
4a16fb |
int i = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
s = strtok(str, ",");
|
|
Packit |
4a16fb |
while ((s != NULL) && (i < SND_SOC_TPLG_MAX_FORMATS)) {
|
|
Packit |
4a16fb |
format = snd_pcm_format_value(s);
|
|
Packit |
4a16fb |
if (format == SND_PCM_FORMAT_UNKNOWN) {
|
|
Packit Service |
f36a15 |
SNDERR("unsupported stream format %s", s);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
caps->formats |= 1ull << format;
|
|
Packit |
4a16fb |
s = strtok(NULL, ", ");
|
|
Packit |
4a16fb |
i++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int get_rate_value(const char* name)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
int rate;
|
|
Packit |
4a16fb |
for (rate = 0; rate <= SND_PCM_RATE_LAST; rate++) {
|
|
Packit |
4a16fb |
if (snd_pcm_rate_names[rate] &&
|
|
Packit |
4a16fb |
strcasecmp(name, snd_pcm_rate_names[rate]) == 0) {
|
|
Packit |
4a16fb |
return rate;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return SND_PCM_RATE_UNKNOWN;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static const char *get_rate_name(int rate)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
if (rate >= 0 && rate <= SND_PCM_RATE_LAST)
|
|
Packit Service |
f36a15 |
return snd_pcm_rate_names[rate];
|
|
Packit Service |
f36a15 |
return NULL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
char *s = NULL;
|
|
Packit |
4a16fb |
snd_pcm_rates_t rate;
|
|
Packit |
4a16fb |
int i = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
s = strtok(str, ",");
|
|
Packit |
4a16fb |
while (s) {
|
|
Packit |
4a16fb |
rate = get_rate_value(s);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (rate == SND_PCM_RATE_UNKNOWN) {
|
|
Packit Service |
f36a15 |
SNDERR("unsupported stream rate %s", s);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
caps->rates |= 1 << rate;
|
|
Packit |
4a16fb |
s = strtok(NULL, ", ");
|
|
Packit |
4a16fb |
i++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static int parse_unsigned(snd_config_t *n, unsigned int *dst)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
int ival;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (tplg_get_integer(n, &ival, 0) < 0)
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
*dst = ival;
|
|
Packit Service |
f36a15 |
#if TPLG_DEBUG
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
const char *id;
|
|
Packit Service |
f36a15 |
if (snd_config_get_id(n, &id) >= 0)
|
|
Packit Service |
f36a15 |
tplg_dbg("\t\t%s: %d", id, *dst);
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
#endif
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* Parse pcm stream capabilities */
|
|
Packit |
4a16fb |
int tplg_parse_stream_caps(snd_tplg_t *tplg,
|
|
Packit Service |
f36a15 |
snd_config_t *cfg,
|
|
Packit Service |
f36a15 |
void *private ATTRIBUTE_UNUSED)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_stream_caps *sc;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit |
4a16fb |
const char *id, *val;
|
|
Packit |
4a16fb |
char *s;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CAPS);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
sc = elem->stream_caps;
|
|
Packit |
4a16fb |
sc->size = elem->size;
|
|
Packit |
4a16fb |
snd_strlcpy(sc->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg(" PCM Capabilities: %s", elem->id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* skip comments */
|
|
Packit |
4a16fb |
if (strcmp(id, "comment") == 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (id[0] == '#')
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "formats") == 0) {
|
|
Packit Service |
f36a15 |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
s = strdup(val);
|
|
Packit |
4a16fb |
if (s == NULL)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = split_format(sc, s);
|
|
Packit |
4a16fb |
free(s);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("\t\t%s: %s", id, val);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "rates") == 0) {
|
|
Packit Service |
f36a15 |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
s = strdup(val);
|
|
Packit |
4a16fb |
if (!s)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = split_rate(sc, s);
|
|
Packit |
4a16fb |
free(s);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("\t\t%s: %s", id, val);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "rate_min") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->rate_min))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "rate_max") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->rate_max))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "channels_min") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->channels_min))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "channels_max") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->channels_max))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "periods_min") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->periods_min))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "periods_max") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->periods_max))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "period_size_min") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->period_size_min))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "period_size_max") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->period_size_max))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "buffer_size_min") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->buffer_size_min))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "buffer_size_max") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->buffer_size_max))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "sig_bits") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &sc->sig_bits))
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* save stream caps */
|
|
Packit Service |
f36a15 |
int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_stream_caps *sc = elem->stream_caps;
|
|
Packit Service |
f36a15 |
const char *s;
|
|
Packit Service |
f36a15 |
unsigned int i;
|
|
Packit Service |
f36a15 |
int err, first;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->formats) {
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tformats '");
|
|
Packit Service |
f36a15 |
first = 1;
|
|
Packit Service |
f36a15 |
for (i = 0; err >= 0 && i < SND_PCM_FORMAT_LAST; i++) {
|
|
Packit Service |
f36a15 |
if (sc->formats & (1ULL << i)) {
|
|
Packit Service |
f36a15 |
s = snd_pcm_format_name(i);
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "%s%s",
|
|
Packit Service |
f36a15 |
!first ? ", " : "", s);
|
|
Packit Service |
f36a15 |
first = 0;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'\n");
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->rates) {
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\trates '");
|
|
Packit Service |
f36a15 |
first = 1;
|
|
Packit Service |
f36a15 |
for (i = 0; err >= 0 && i < SND_PCM_RATE_LAST; i++) {
|
|
Packit Service |
f36a15 |
if (sc->rates & (1ULL << i)) {
|
|
Packit Service |
f36a15 |
s = get_rate_name(i);
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "%s%s",
|
|
Packit Service |
f36a15 |
!first ? ", " : "", s);
|
|
Packit Service |
f36a15 |
first = 0;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'\n");
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->rate_min)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\trate_min %u\n",
|
|
Packit Service |
f36a15 |
sc->rate_min);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->rate_max)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\trate_max %u\n",
|
|
Packit Service |
f36a15 |
sc->rate_max);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->channels_min)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tchannels_min %u\n",
|
|
Packit Service |
f36a15 |
sc->channels_min);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->channels_max)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tchannels_max %u\n",
|
|
Packit Service |
f36a15 |
sc->channels_max);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->periods_min)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tperiods_min %u\n",
|
|
Packit Service |
f36a15 |
sc->periods_min);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->periods_max)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tperiods_max %u\n",
|
|
Packit Service |
f36a15 |
sc->periods_max);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->period_size_min)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tperiod_size_min %u\n",
|
|
Packit Service |
f36a15 |
sc->period_size_min);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->period_size_max)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tperiod_size_max %u\n",
|
|
Packit Service |
f36a15 |
sc->period_size_max);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->buffer_size_min)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tbuffer_size_min %u\n",
|
|
Packit Service |
f36a15 |
sc->buffer_size_min);
|
|
Packit Service |
f36a15 |
if (err >= 0 && sc->buffer_size_max)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tbuffer_size_max %u\n",
|
|
Packit Service |
f36a15 |
sc->buffer_size_max);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* Parse the caps and config of a pcm stream */
|
|
Packit |
4a16fb |
static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit |
4a16fb |
snd_config_t *cfg, void *private)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit |
4a16fb |
struct tplg_elem *elem = private;
|
|
Packit |
4a16fb |
struct snd_soc_tplg_pcm *pcm;
|
|
Packit |
4a16fb |
struct snd_soc_tplg_dai *dai;
|
|
Packit |
4a16fb |
unsigned int *playback, *capture;
|
|
Packit |
4a16fb |
struct snd_soc_tplg_stream_caps *caps;
|
|
Packit |
4a16fb |
const char *id, *value;
|
|
Packit |
4a16fb |
int stream;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_get_id(cfg, &id;;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("\t%s:", id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
switch (elem->type) {
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_PCM:
|
|
Packit |
4a16fb |
pcm = elem->pcm;
|
|
Packit |
4a16fb |
playback = &pcm->playback;
|
|
Packit |
4a16fb |
capture = &pcm->capture;
|
|
Packit |
4a16fb |
caps = pcm->caps;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
case SND_TPLG_TYPE_DAI:
|
|
Packit |
4a16fb |
dai = elem->dai;
|
|
Packit |
4a16fb |
playback = &dai->playback;
|
|
Packit |
4a16fb |
capture = &dai->capture;
|
|
Packit |
4a16fb |
caps = dai->caps;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
default:
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "playback") == 0) {
|
|
Packit |
4a16fb |
stream = SND_SOC_TPLG_STREAM_PLAYBACK;
|
|
Packit |
4a16fb |
*playback = 1;
|
|
Packit |
4a16fb |
} else if (strcmp(id, "capture") == 0) {
|
|
Packit |
4a16fb |
stream = SND_SOC_TPLG_STREAM_CAPTURE;
|
|
Packit |
4a16fb |
*capture = 1;
|
|
Packit |
4a16fb |
} else
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* get id */
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "capabilities") == 0) {
|
|
Packit |
4a16fb |
if (snd_config_get_string(n, &value) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
/* store stream caps name, to find and merge
|
|
Packit |
4a16fb |
* the caps in building phase.
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
snd_strlcpy(caps[stream].name, value,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("\t\t%s\n\t\t\t%s", id, value);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* Save the caps and config of a pcm stream */
|
|
Packit Service |
f36a15 |
int tplg_save_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
static const char *stream_ids[2] = {
|
|
Packit Service |
f36a15 |
"playback",
|
|
Packit Service |
f36a15 |
"capture"
|
|
Packit Service |
f36a15 |
};
|
|
Packit Service |
f36a15 |
static unsigned int stream_types[2] = {
|
|
Packit Service |
f36a15 |
SND_SOC_TPLG_STREAM_PLAYBACK,
|
|
Packit Service |
f36a15 |
SND_SOC_TPLG_STREAM_CAPTURE
|
|
Packit Service |
f36a15 |
};
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_stream_caps *caps;
|
|
Packit Service |
f36a15 |
unsigned int streams[2], stream;
|
|
Packit Service |
f36a15 |
const char *s;
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
switch (elem->type) {
|
|
Packit Service |
f36a15 |
case SND_TPLG_TYPE_PCM:
|
|
Packit Service |
f36a15 |
streams[0] = elem->pcm->playback;
|
|
Packit Service |
f36a15 |
streams[1] = elem->pcm->capture;
|
|
Packit Service |
f36a15 |
caps = elem->pcm->caps;
|
|
Packit Service |
f36a15 |
break;
|
|
Packit Service |
f36a15 |
case SND_TPLG_TYPE_DAI:
|
|
Packit Service |
f36a15 |
streams[0] = elem->dai->playback;
|
|
Packit Service |
f36a15 |
streams[1] = elem->dai->capture;
|
|
Packit Service |
f36a15 |
caps = elem->dai->caps;
|
|
Packit Service |
f36a15 |
break;
|
|
Packit Service |
f36a15 |
default:
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
for (stream = 0; stream < 2; stream++) {
|
|
Packit Service |
f36a15 |
if (streams[stream] == 0)
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
if (!caps)
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
s = caps[stream_types[stream]].name;
|
|
Packit Service |
f36a15 |
if (s[0] == '\0')
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "pcm.%s {\n", stream_ids[stream]);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tcapabilities '%s'\n", s);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* Parse name and id of a front-end DAI (ie. cpu dai of a FE DAI link) */
|
|
Packit |
4a16fb |
static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit |
4a16fb |
snd_config_t *cfg, void *private)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct tplg_elem *elem = private;
|
|
Packit |
4a16fb |
struct snd_soc_tplg_pcm *pcm = elem->pcm;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit Service |
f36a15 |
const char *id;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_get_id(cfg, &id;;
|
|
Packit Service |
f36a15 |
tplg_dbg("\t\tFE DAI %s:", id);
|
|
Packit |
4a16fb |
snd_strlcpy(pcm->dai_name, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* get id */
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit Service |
f36a15 |
if (tplg_get_unsigned(n, &pcm->dai_id, 0)) {
|
|
Packit Service |
f36a15 |
SNDERR("invalid fe dai ID");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("\t\t\tindex: %d", pcm->dai_id);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* Save the caps and config of a pcm stream */
|
|
Packit Service |
f36a15 |
int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_pcm *pcm = elem->pcm;
|
|
Packit Service |
f36a15 |
int err = 0;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (pcm->dai_id > 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "dai.0.id %u\n", pcm->dai_id);
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* parse a flag bit of the given mask */
|
|
Packit |
4a16fb |
static int parse_flag(snd_config_t *n, unsigned int mask_in,
|
|
Packit |
4a16fb |
unsigned int *mask, unsigned int *flags)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
int ret;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
ret = snd_config_get_bool(n);
|
|
Packit |
4a16fb |
if (ret < 0)
|
|
Packit |
4a16fb |
return ret;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
*mask |= mask_in;
|
|
Packit |
4a16fb |
if (ret)
|
|
Packit |
4a16fb |
*flags |= mask_in;
|
|
Packit |
4a16fb |
else
|
|
Packit |
4a16fb |
*flags &= ~mask_in;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static int save_flags(unsigned int flags, unsigned int mask,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
static unsigned int flag_masks[3] = {
|
|
Packit Service |
f36a15 |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES,
|
|
Packit Service |
f36a15 |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS,
|
|
Packit Service |
f36a15 |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS,
|
|
Packit Service |
f36a15 |
};
|
|
Packit Service |
f36a15 |
static const char *flag_ids[3] = {
|
|
Packit Service |
f36a15 |
"symmetric_rates",
|
|
Packit Service |
f36a15 |
"symmetric_channels",
|
|
Packit Service |
f36a15 |
"symmetric_sample_bits",
|
|
Packit Service |
f36a15 |
};
|
|
Packit Service |
f36a15 |
unsigned int i;
|
|
Packit Service |
f36a15 |
int err = 0;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
for (i = 0; err >= 0 && i < ARRAY_SIZE(flag_masks); i++) {
|
|
Packit Service |
f36a15 |
if (mask & flag_masks[i]) {
|
|
Packit Service |
f36a15 |
unsigned int v = (flags & flag_masks[i]) ? 1 : 0;
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "%s %u\n",
|
|
Packit Service |
f36a15 |
flag_ids[i], v);
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* Parse PCM (for front end DAI & DAI link) in text conf file */
|
|
Packit Service |
f36a15 |
int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
Packit Service |
f36a15 |
void *private ATTRIBUTE_UNUSED)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_pcm *pcm;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit Service |
f36a15 |
const char *id;
|
|
Packit Service |
f36a15 |
int err, ival;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_PCM);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
pcm = elem->pcm;
|
|
Packit |
4a16fb |
pcm->size = elem->size;
|
|
Packit |
4a16fb |
snd_strlcpy(pcm->pcm_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg(" PCM: %s", elem->id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* skip comments */
|
|
Packit |
4a16fb |
if (strcmp(id, "comment") == 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (id[0] == '#')
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &pcm->pcm_id))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "pcm") == 0) {
|
|
Packit |
4a16fb |
err = tplg_parse_compound(tplg, n,
|
|
Packit |
4a16fb |
tplg_parse_streams, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "compress") == 0) {
|
|
Packit Service |
f36a15 |
ival = snd_config_get_bool(n);
|
|
Packit Service |
f36a15 |
if (ival < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
pcm->compress = ival;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("\t%s: %d", id, ival);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "dai") == 0) {
|
|
Packit |
4a16fb |
err = tplg_parse_compound(tplg, n,
|
|
Packit |
4a16fb |
tplg_parse_fe_dai, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* flags */
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_rates") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES,
|
|
Packit |
4a16fb |
&pcm->flag_mask, &pcm->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_channels") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS,
|
|
Packit |
4a16fb |
&pcm->flag_mask, &pcm->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_sample_bits") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS,
|
|
Packit |
4a16fb |
&pcm->flag_mask, &pcm->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* private data */
|
|
Packit |
4a16fb |
if (strcmp(id, "data") == 0) {
|
|
Packit Service |
f36a15 |
err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* save PCM */
|
|
Packit Service |
f36a15 |
int tplg_save_pcm(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_pcm *pcm = elem->pcm;
|
|
Packit Service |
f36a15 |
char pfx2[16];
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && elem->index)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tindex %u\n",
|
|
Packit Service |
f36a15 |
elem->index);
|
|
Packit Service |
f36a15 |
if (err >= 0 && pcm->pcm_id)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tid %u\n",
|
|
Packit Service |
f36a15 |
pcm->pcm_id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && pcm->compress)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tcompress 1\n");
|
|
Packit Service |
f36a15 |
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_fe_dai(tplg, elem, dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_streams(tplg, elem, dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = save_flags(pcm->flags, pcm->flag_mask, dst, pfx);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
|
|
Packit Service |
f36a15 |
"data", dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* Parse physical DAI */
|
|
Packit Service |
f36a15 |
int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
Packit Service |
f36a15 |
void *private ATTRIBUTE_UNUSED)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_dai *dai;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit Service |
f36a15 |
const char *id;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAI);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
dai = elem->dai;
|
|
Packit |
4a16fb |
dai->size = elem->size;
|
|
Packit |
4a16fb |
snd_strlcpy(dai->dai_name, elem->id,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg(" DAI: %s", elem->id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* skip comments */
|
|
Packit |
4a16fb |
if (strcmp(id, "comment") == 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (id[0] == '#')
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &dai->dai_id))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "playback") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &dai->playback))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "capture") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &dai->capture))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* stream capabilities */
|
|
Packit |
4a16fb |
if (strcmp(id, "pcm") == 0) {
|
|
Packit |
4a16fb |
err = tplg_parse_compound(tplg, n,
|
|
Packit |
4a16fb |
tplg_parse_streams, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* flags */
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_rates") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES,
|
|
Packit |
4a16fb |
&dai->flag_mask, &dai->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_channels") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS,
|
|
Packit |
4a16fb |
&dai->flag_mask, &dai->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_sample_bits") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS,
|
|
Packit |
4a16fb |
&dai->flag_mask, &dai->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* private data */
|
|
Packit |
4a16fb |
if (strcmp(id, "data") == 0) {
|
|
Packit Service |
f36a15 |
err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* save DAI */
|
|
Packit Service |
f36a15 |
int tplg_save_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_dai *dai = elem->dai;
|
|
Packit Service |
f36a15 |
char pfx2[16];
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (!dai)
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && elem->index)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tindex %u\n",
|
|
Packit Service |
f36a15 |
elem->index);
|
|
Packit Service |
f36a15 |
if (err >= 0 && dai->dai_id)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tid %u\n",
|
|
Packit Service |
f36a15 |
dai->dai_id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && dai->playback)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tplayback %u\n",
|
|
Packit Service |
f36a15 |
dai->playback);
|
|
Packit Service |
f36a15 |
if (err >= 0 && dai->capture)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tcapture %u\n",
|
|
Packit Service |
f36a15 |
dai->capture);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_streams(tplg, elem, dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = save_flags(dai->flags, dai->flag_mask, dst, pfx);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
|
|
Packit Service |
f36a15 |
"data", dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* parse physical link runtime supported HW configs in text conf file */
|
|
Packit |
4a16fb |
static int parse_hw_config_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit |
4a16fb |
snd_config_t *cfg,
|
|
Packit |
4a16fb |
struct tplg_elem *elem)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_link_config *link = elem->link;
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
err = tplg_parse_refs(cfg, elem, SND_TPLG_TYPE_HW_CONFIG);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
link->num_hw_configs = err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* Parse a physical link element in text conf file */
|
|
Packit Service |
f36a15 |
int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
Packit Service |
f36a15 |
void *private ATTRIBUTE_UNUSED)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_link_config *link;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit |
4a16fb |
const char *id, *val = NULL;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BE);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
link = elem->link;
|
|
Packit |
4a16fb |
link->size = elem->size;
|
|
Packit |
4a16fb |
snd_strlcpy(link->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg(" Link: %s", elem->id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* skip comments */
|
|
Packit |
4a16fb |
if (strcmp(id, "comment") == 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (id[0] == '#')
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &link->id))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "stream_name") == 0) {
|
|
Packit |
4a16fb |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_strlcpy(link->stream_name, val,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit Service |
f36a15 |
tplg_dbg("\t%s: %s", id, val);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "hw_configs") == 0) {
|
|
Packit |
4a16fb |
err = parse_hw_config_refs(tplg, n, elem);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "default_hw_conf_id") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &link->default_hw_config_id))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* flags */
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_rates") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES,
|
|
Packit |
4a16fb |
&link->flag_mask, &link->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_channels") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS,
|
|
Packit |
4a16fb |
&link->flag_mask, &link->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "symmetric_sample_bits") == 0) {
|
|
Packit |
4a16fb |
err = parse_flag(n,
|
|
Packit |
4a16fb |
SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS,
|
|
Packit |
4a16fb |
&link->flag_mask, &link->flags);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* private data */
|
|
Packit |
4a16fb |
if (strcmp(id, "data") == 0) {
|
|
Packit Service |
f36a15 |
err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* save physical link */
|
|
Packit Service |
f36a15 |
int tplg_save_link(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_link_config *link = elem->link;
|
|
Packit Service |
f36a15 |
char pfx2[16];
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (!link)
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && elem->index)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tindex %u\n",
|
|
Packit Service |
f36a15 |
elem->index);
|
|
Packit Service |
f36a15 |
if (err >= 0 && link->id)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tid %u\n",
|
|
Packit Service |
f36a15 |
link->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && link->stream_name[0])
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tstream_name '%s'\n",
|
|
Packit Service |
f36a15 |
link->stream_name);
|
|
Packit Service |
f36a15 |
if (err >= 0 && link->default_hw_config_id)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tdefault_hw_conf_id %u\n",
|
|
Packit Service |
f36a15 |
link->default_hw_config_id);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = save_flags(link->flags, link->flag_mask, dst, pfx);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_HW_CONFIG,
|
|
Packit Service |
f36a15 |
"hw_configs", dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
|
|
Packit Service |
f36a15 |
"data", dst, pfx2);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* Parse cc */
|
|
Packit Service |
f36a15 |
int tplg_parse_cc(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
Packit Service |
f36a15 |
void *private ATTRIBUTE_UNUSED)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_soc_tplg_link_config *link;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit Service |
f36a15 |
const char *id;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_CC);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
link = elem->link;
|
|
Packit |
4a16fb |
link->size = elem->size;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg(" CC: %s", elem->id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* skip comments */
|
|
Packit |
4a16fb |
if (strcmp(id, "comment") == 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (id[0] == '#')
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &link->id))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* save CC */
|
|
Packit Service |
f36a15 |
int tplg_save_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit |
4a16fb |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_link_config *link = elem->link;
|
|
Packit Service |
f36a15 |
char pfx2[16];
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
if (!link)
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && elem->index)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tindex %u\n",
|
|
Packit Service |
f36a15 |
elem->index);
|
|
Packit Service |
f36a15 |
if (err >= 0 && link->id)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tid %u\n",
|
|
Packit Service |
f36a15 |
link->id);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
struct audio_hw_format {
|
|
Packit Service |
f36a15 |
unsigned int type;
|
|
Packit Service |
f36a15 |
const char *name;
|
|
Packit Service |
f36a15 |
};
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static struct audio_hw_format audio_hw_formats[] = {
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_I2S,
|
|
Packit Service |
f36a15 |
.name = "I2S",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_RIGHT_J,
|
|
Packit Service |
f36a15 |
.name = "RIGHT_J",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_LEFT_J,
|
|
Packit Service |
f36a15 |
.name = "LEFT_J",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_DSP_A,
|
|
Packit Service |
f36a15 |
.name = "DSP_A",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_DSP_B,
|
|
Packit Service |
f36a15 |
.name = "DSP_B",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_AC97,
|
|
Packit Service |
f36a15 |
.name = "AC97",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_AC97,
|
|
Packit Service |
f36a15 |
.name = "AC97",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
.type = SND_SOC_DAI_FORMAT_PDM,
|
|
Packit Service |
f36a15 |
.name = "PDM",
|
|
Packit Service |
f36a15 |
},
|
|
Packit Service |
f36a15 |
};
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static int get_audio_hw_format(const char *val)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
unsigned int i;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
if (val[0] == '\0')
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
for (i = 0; i < ARRAY_SIZE(audio_hw_formats); i++)
|
|
Packit Service |
f36a15 |
if (strcasecmp(audio_hw_formats[i].name, val) == 0)
|
|
Packit Service |
f36a15 |
return audio_hw_formats[i].type;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
SNDERR("invalid audio HW format %s", val);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static const char *get_audio_hw_format_name(unsigned int type)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
unsigned int i;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
for (i = 0; i < ARRAY_SIZE(audio_hw_formats); i++)
|
|
Packit Service |
f36a15 |
if (audio_hw_formats[i].type == type)
|
|
Packit Service |
f36a15 |
return audio_hw_formats[i].name;
|
|
Packit Service |
f36a15 |
return NULL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
Packit |
4a16fb |
void *private ATTRIBUTE_UNUSED)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
struct snd_soc_tplg_hw_config *hw_cfg;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *n;
|
|
Packit |
4a16fb |
const char *id, *val = NULL;
|
|
Packit Service |
f36a15 |
int ret, ival;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
hw_cfg = elem->hw_cfg;
|
|
Packit |
4a16fb |
hw_cfg->size = elem->size;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg(" Link HW config: %s", elem->id);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, cfg) {
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* skip comments */
|
|
Packit |
4a16fb |
if (strcmp(id, "comment") == 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (id[0] == '#')
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->id))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "format") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "fmt") == 0) {
|
|
Packit |
4a16fb |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
ret = get_audio_hw_format(val);
|
|
Packit |
4a16fb |
if (ret < 0)
|
|
Packit |
4a16fb |
return ret;
|
|
Packit |
4a16fb |
hw_cfg->fmt = ret;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "bclk") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "bclk_master") == 0) {
|
|
Packit |
4a16fb |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (!strcmp(val, "master")) {
|
|
Packit |
4a16fb |
/* For backwards capability,
|
|
Packit |
4a16fb |
* "master" == "codec is slave"
|
|
Packit |
4a16fb |
*/
|
|
Packit Service |
f36a15 |
SNDERR("deprecated bclk value '%s'", val);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS;
|
|
Packit |
4a16fb |
} else if (!strcmp(val, "codec_slave")) {
|
|
Packit |
4a16fb |
hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS;
|
|
Packit |
4a16fb |
} else if (!strcmp(val, "codec_master")) {
|
|
Packit |
4a16fb |
hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "bclk_freq") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "bclk_rate") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->bclk_rate))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "bclk_invert") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "invert_bclk") == 0) {
|
|
Packit Service |
f36a15 |
ival = snd_config_get_bool(n);
|
|
Packit Service |
f36a15 |
if (ival < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
hw_cfg->invert_bclk = ival;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "fsync") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "fsync_master") == 0) {
|
|
Packit |
4a16fb |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (!strcmp(val, "master")) {
|
|
Packit |
4a16fb |
/* For backwards capability,
|
|
Packit |
4a16fb |
* "master" == "codec is slave"
|
|
Packit |
4a16fb |
*/
|
|
Packit Service |
f36a15 |
SNDERR("deprecated fsync value '%s'", val);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS;
|
|
Packit |
4a16fb |
} else if (!strcmp(val, "codec_slave")) {
|
|
Packit |
4a16fb |
hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS;
|
|
Packit |
4a16fb |
} else if (!strcmp(val, "codec_master")) {
|
|
Packit |
4a16fb |
hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "fsync_invert") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "invert_fsync") == 0) {
|
|
Packit Service |
f36a15 |
ival = snd_config_get_bool(n);
|
|
Packit Service |
f36a15 |
if (ival < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
hw_cfg->invert_fsync = ival;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "fsync_freq") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "fsync_rate") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->fsync_rate))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "mclk_freq") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "mclk_rate") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->mclk_rate))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "mclk") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "mclk_direction") == 0) {
|
|
Packit |
4a16fb |
if (snd_config_get_string(n, &val) < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (!strcmp(val, "master")) {
|
|
Packit |
4a16fb |
/* For backwards capability,
|
|
Packit |
4a16fb |
* "master" == "for codec, mclk is input"
|
|
Packit |
4a16fb |
*/
|
|
Packit Service |
f36a15 |
SNDERR("deprecated mclk value '%s'", val);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CI;
|
|
Packit |
4a16fb |
} else if (!strcmp(val, "codec_mclk_in")) {
|
|
Packit |
4a16fb |
hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CI;
|
|
Packit |
4a16fb |
} else if (!strcmp(val, "codec_mclk_out")) {
|
|
Packit |
4a16fb |
hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CO;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "pm_gate_clocks") == 0 ||
|
|
Packit |
4a16fb |
strcmp(id, "clock_gated") == 0) {
|
|
Packit Service |
f36a15 |
ival = snd_config_get_bool(n);
|
|
Packit Service |
f36a15 |
if (ival < 0)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
if (ival)
|
|
Packit |
4a16fb |
hw_cfg->clock_gated =
|
|
Packit |
4a16fb |
SND_SOC_TPLG_DAI_CLK_GATE_GATED;
|
|
Packit |
4a16fb |
else
|
|
Packit |
4a16fb |
hw_cfg->clock_gated =
|
|
Packit |
4a16fb |
SND_SOC_TPLG_DAI_CLK_GATE_CONT;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "tdm_slots") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->tdm_slots))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "tdm_slot_width") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->tdm_slot_width))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "tx_slots") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->tx_slots))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "rx_slots") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->rx_slots))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "tx_channels") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->tx_channels))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (strcmp(id, "rx_channels") == 0) {
|
|
Packit Service |
f36a15 |
if (parse_unsigned(n, &hw_cfg->rx_channels))
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
/* save hw config */
|
|
Packit Service |
f36a15 |
int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem,
|
|
Packit Service |
f36a15 |
char **dst, const char *pfx)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_hw_config *hc = elem->hw_cfg;
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->id)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tid %u\n",
|
|
Packit Service |
f36a15 |
hc->id);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->fmt)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tformat '%s'\n",
|
|
Packit Service |
f36a15 |
get_audio_hw_format_name(hc->fmt));
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->bclk_master)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tbclk '%s'\n",
|
|
Packit Service |
f36a15 |
hc->bclk_master == SND_SOC_TPLG_BCLK_CS ?
|
|
Packit Service |
f36a15 |
"codec_slave" : "codec_master");
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->bclk_rate)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tbclk_freq %u\n",
|
|
Packit Service |
f36a15 |
hc->bclk_rate);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->invert_bclk)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tbclk_invert 1\n");
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->fsync_master)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tfsync_master '%s'\n",
|
|
Packit Service |
f36a15 |
hc->fsync_master == SND_SOC_TPLG_FSYNC_CS ?
|
|
Packit Service |
f36a15 |
"codec_slave" : "codec_master");
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->fsync_rate)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tfsync_freq %u\n",
|
|
Packit Service |
f36a15 |
hc->fsync_rate);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->invert_fsync)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tfsync_invert 1\n");
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->mclk_rate)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tmclk_freq %u\n",
|
|
Packit Service |
f36a15 |
hc->mclk_rate);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->mclk_direction)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tmclk '%s'\n",
|
|
Packit Service |
f36a15 |
hc->mclk_direction == SND_SOC_TPLG_MCLK_CI ?
|
|
Packit Service |
f36a15 |
"codec_mclk_in" : "codec_mclk_out");
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->clock_gated)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\tpm_gate_clocks 1\n");
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->tdm_slots)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\ttdm_slots %u\n",
|
|
Packit Service |
f36a15 |
hc->tdm_slots);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->tdm_slot_width)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\ttdm_slot_width %u\n",
|
|
Packit Service |
f36a15 |
hc->tdm_slot_width);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->tx_slots)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\ttx_slots %u\n",
|
|
Packit Service |
f36a15 |
hc->tx_slots);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->rx_slots)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\trx_slots %u\n",
|
|
Packit Service |
f36a15 |
hc->rx_slots);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->tx_channels)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\ttx_channels %u\n",
|
|
Packit Service |
f36a15 |
hc->tx_channels);
|
|
Packit Service |
f36a15 |
if (err >= 0 && hc->rx_channels)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "\trx_channels %u\n",
|
|
Packit Service |
f36a15 |
hc->rx_channels);
|
|
Packit Service |
f36a15 |
if (err >= 0)
|
|
Packit Service |
f36a15 |
err = tplg_save_printf(dst, pfx, "}\n");
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit |
4a16fb |
/* copy stream object */
|
|
Packit |
4a16fb |
static void tplg_add_stream_object(struct snd_soc_tplg_stream *strm,
|
|
Packit Service |
f36a15 |
struct snd_tplg_stream_template *strm_tpl)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_strlcpy(strm->name, strm_tpl->name,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
strm->format = strm_tpl->format;
|
|
Packit |
4a16fb |
strm->rate = strm_tpl->rate;
|
|
Packit |
4a16fb |
strm->period_bytes = strm_tpl->period_bytes;
|
|
Packit |
4a16fb |
strm->buffer_bytes = strm_tpl->buffer_bytes;
|
|
Packit |
4a16fb |
strm->channels = strm_tpl->channels;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
static int tplg_add_stream_caps(snd_tplg_t *tplg,
|
|
Packit Service |
f36a15 |
struct snd_tplg_stream_caps_template *caps_tpl)
|
|
Packit |
4a16fb |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_stream_caps *caps;
|
|
Packit Service |
f36a15 |
struct tplg_elem *elem;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
elem = tplg_elem_new_common(tplg, NULL, caps_tpl->name,
|
|
Packit Service |
f36a15 |
SND_TPLG_TYPE_STREAM_CAPS);
|
|
Packit Service |
f36a15 |
if (!elem)
|
|
Packit Service |
f36a15 |
return -ENOMEM;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
caps = elem->stream_caps;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
snd_strlcpy(caps->name, caps_tpl->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
caps->formats = caps_tpl->formats;
|
|
Packit |
4a16fb |
caps->rates = caps_tpl->rates;
|
|
Packit |
4a16fb |
caps->rate_min = caps_tpl->rate_min;
|
|
Packit |
4a16fb |
caps->rate_max = caps_tpl->rate_max;
|
|
Packit |
4a16fb |
caps->channels_min = caps_tpl->channels_min;
|
|
Packit |
4a16fb |
caps->channels_max = caps_tpl->channels_max;
|
|
Packit |
4a16fb |
caps->periods_min = caps_tpl->periods_min;
|
|
Packit |
4a16fb |
caps->periods_max = caps_tpl->periods_max;
|
|
Packit |
4a16fb |
caps->period_size_min = caps_tpl->period_size_min;
|
|
Packit |
4a16fb |
caps->period_size_max = caps_tpl->period_size_max;
|
|
Packit |
4a16fb |
caps->buffer_size_min = caps_tpl->buffer_size_min;
|
|
Packit |
4a16fb |
caps->buffer_size_max = caps_tpl->buffer_size_max;
|
|
Packit |
4a16fb |
caps->sig_bits = caps_tpl->sig_bits;
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* Add a PCM element (FE DAI & DAI link) from C API */
|
|
Packit |
4a16fb |
int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_tplg_pcm_template *pcm_tpl = t->pcm;
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_private *priv;
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_pcm *pcm;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit Service |
f36a15 |
int ret, i;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("PCM: %s, DAI %s", pcm_tpl->pcm_name, pcm_tpl->dai_name);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (pcm_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, NULL, pcm_tpl->pcm_name,
|
|
Packit |
4a16fb |
SND_TPLG_TYPE_PCM);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
pcm = elem->pcm;
|
|
Packit |
4a16fb |
pcm->size = elem->size;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_strlcpy(pcm->pcm_name, pcm_tpl->pcm_name,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
snd_strlcpy(pcm->dai_name, pcm_tpl->dai_name,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
pcm->pcm_id = pcm_tpl->pcm_id;
|
|
Packit |
4a16fb |
pcm->dai_id = pcm_tpl->dai_id;
|
|
Packit |
4a16fb |
pcm->playback = pcm_tpl->playback;
|
|
Packit |
4a16fb |
pcm->capture = pcm_tpl->capture;
|
|
Packit |
4a16fb |
pcm->compress = pcm_tpl->compress;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (i = 0; i < 2; i++) {
|
|
Packit Service |
f36a15 |
if (!pcm_tpl->caps[i] || !pcm_tpl->caps[i]->name)
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
ret = tplg_add_stream_caps(tplg, pcm_tpl->caps[i]);
|
|
Packit Service |
f36a15 |
if (ret < 0)
|
|
Packit Service |
f36a15 |
return ret;
|
|
Packit Service |
f36a15 |
snd_strlcpy(pcm->caps[i].name, pcm_tpl->caps[i]->name,
|
|
Packit Service |
f36a15 |
sizeof(pcm->caps[i].name));
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
pcm->flag_mask = pcm_tpl->flag_mask;
|
|
Packit |
4a16fb |
pcm->flags = pcm_tpl->flags;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
pcm->num_streams = pcm_tpl->num_streams;
|
|
Packit |
4a16fb |
for (i = 0; i < pcm_tpl->num_streams; i++)
|
|
Packit |
4a16fb |
tplg_add_stream_object(&pcm->stream[i], &pcm_tpl->stream[i]);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* private data */
|
|
Packit Service |
f36a15 |
priv = pcm_tpl->priv;
|
|
Packit Service |
f36a15 |
if (priv && priv->size > 0) {
|
|
Packit Service |
f36a15 |
ret = tplg_add_data(tplg, elem, priv,
|
|
Packit Service |
f36a15 |
sizeof(*priv) + priv->size);
|
|
Packit Service |
f36a15 |
if (ret < 0)
|
|
Packit Service |
f36a15 |
return ret;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* Set link HW config from C API template */
|
|
Packit |
4a16fb |
static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg,
|
|
Packit Service |
f36a15 |
struct snd_tplg_hw_config_template *tpl)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int i;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
cfg->size = sizeof(*cfg);
|
|
Packit |
4a16fb |
cfg->id = tpl->id;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
cfg->fmt = tpl->fmt;
|
|
Packit |
4a16fb |
cfg->clock_gated = tpl->clock_gated;
|
|
Packit |
4a16fb |
cfg->invert_bclk = tpl->invert_bclk;
|
|
Packit |
4a16fb |
cfg->invert_fsync = tpl->invert_fsync;
|
|
Packit |
4a16fb |
cfg->bclk_master = tpl->bclk_master;
|
|
Packit |
4a16fb |
cfg->fsync_master = tpl->fsync_master;
|
|
Packit |
4a16fb |
cfg->mclk_direction = tpl->mclk_direction;
|
|
Packit |
4a16fb |
cfg->reserved = tpl->reserved;
|
|
Packit |
4a16fb |
cfg->mclk_rate = tpl->mclk_rate;
|
|
Packit |
4a16fb |
cfg->bclk_rate = tpl->bclk_rate;
|
|
Packit |
4a16fb |
cfg->fsync_rate = tpl->fsync_rate;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
cfg->tdm_slots = tpl->tdm_slots;
|
|
Packit |
4a16fb |
cfg->tdm_slot_width = tpl->tdm_slot_width;
|
|
Packit |
4a16fb |
cfg->tx_slots = tpl->tx_slots;
|
|
Packit |
4a16fb |
cfg->rx_slots = tpl->rx_slots;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (cfg->tx_channels > SND_SOC_TPLG_MAX_CHAN
|
|
Packit |
4a16fb |
|| cfg->rx_channels > SND_SOC_TPLG_MAX_CHAN)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
cfg->tx_channels = tpl->tx_channels;
|
|
Packit |
4a16fb |
for (i = 0; i < cfg->tx_channels; i++)
|
|
Packit |
4a16fb |
cfg->tx_chanmap[i] = tpl->tx_chanmap[i];
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
cfg->rx_channels = tpl->rx_channels;
|
|
Packit |
4a16fb |
for (i = 0; i < cfg->rx_channels; i++)
|
|
Packit |
4a16fb |
cfg->rx_chanmap[i] = tpl->rx_chanmap[i];
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* Add a physical DAI link element from C API */
|
|
Packit |
4a16fb |
int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_tplg_link_template *link_tpl = t->link;
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_link_config *link;
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_private *priv;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit |
4a16fb |
unsigned int i;
|
|
Packit Service |
f36a15 |
int ret;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (t->type != SND_TPLG_TYPE_LINK && t->type != SND_TPLG_TYPE_BE
|
|
Packit |
4a16fb |
&& t->type != SND_TPLG_TYPE_CC)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, NULL, link_tpl->name, t->type);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
tplg_dbg("Link: %s", link_tpl->name);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
link = elem->link;
|
|
Packit |
4a16fb |
link->size = elem->size;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* ID and names */
|
|
Packit |
4a16fb |
link->id = link_tpl->id;
|
|
Packit |
4a16fb |
snd_strlcpy(link->name, link_tpl->name,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
snd_strlcpy(link->stream_name, link_tpl->stream_name,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* stream configs */
|
|
Packit |
4a16fb |
if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
link->num_streams = link_tpl->num_streams;
|
|
Packit |
4a16fb |
for (i = 0; i < link->num_streams; i++)
|
|
Packit |
4a16fb |
tplg_add_stream_object(&link->stream[i], &link_tpl->stream[i]);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* HW configs */
|
|
Packit |
4a16fb |
if (link_tpl->num_hw_configs > SND_SOC_TPLG_HW_CONFIG_MAX)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
link->num_hw_configs = link_tpl->num_hw_configs;
|
|
Packit |
4a16fb |
link->default_hw_config_id = link_tpl->default_hw_config_id;
|
|
Packit |
4a16fb |
for (i = 0; i < link->num_hw_configs; i++)
|
|
Packit |
4a16fb |
set_link_hw_config(&link->hw_config[i], &link_tpl->hw_config[i]);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* flags */
|
|
Packit |
4a16fb |
link->flag_mask = link_tpl->flag_mask;
|
|
Packit |
4a16fb |
link->flags = link_tpl->flags;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* private data */
|
|
Packit Service |
f36a15 |
priv = link_tpl->priv;
|
|
Packit Service |
f36a15 |
if (priv && priv->size > 0) {
|
|
Packit Service |
f36a15 |
ret = tplg_add_data(tplg, elem, priv,
|
|
Packit Service |
f36a15 |
sizeof(*priv) + priv->size);
|
|
Packit Service |
f36a15 |
if (ret < 0)
|
|
Packit Service |
f36a15 |
return ret;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct snd_tplg_dai_template *dai_tpl = t->dai;
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_dai *dai;
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_private *priv;
|
|
Packit |
4a16fb |
struct tplg_elem *elem;
|
|
Packit Service |
f36a15 |
int ret, i;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
tplg_dbg("DAI %s", dai_tpl->dai_name);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
elem = tplg_elem_new_common(tplg, NULL, dai_tpl->dai_name,
|
|
Packit Service |
f36a15 |
SND_TPLG_TYPE_DAI);
|
|
Packit |
4a16fb |
if (!elem)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
dai = elem->dai;
|
|
Packit |
4a16fb |
dai->size = elem->size;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_strlcpy(dai->dai_name, dai_tpl->dai_name,
|
|
Packit |
4a16fb |
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
Packit |
4a16fb |
dai->dai_id = dai_tpl->dai_id;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* stream caps */
|
|
Packit |
4a16fb |
dai->playback = dai_tpl->playback;
|
|
Packit |
4a16fb |
dai->capture = dai_tpl->capture;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (i = 0; i < 2; i++) {
|
|
Packit Service |
f36a15 |
if (!dai_tpl->caps[i] || !dai_tpl->caps[i]->name)
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
ret = tplg_add_stream_caps(tplg, dai_tpl->caps[i]);
|
|
Packit Service |
f36a15 |
if (ret < 0)
|
|
Packit Service |
f36a15 |
return ret;
|
|
Packit Service |
f36a15 |
snd_strlcpy(dai->caps[i].name, dai_tpl->caps[i]->name,
|
|
Packit Service |
f36a15 |
sizeof(dai->caps[i].name));
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* flags */
|
|
Packit |
4a16fb |
dai->flag_mask = dai_tpl->flag_mask;
|
|
Packit |
4a16fb |
dai->flags = dai_tpl->flags;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* private data */
|
|
Packit Service |
f36a15 |
priv = dai_tpl->priv;
|
|
Packit Service |
f36a15 |
if (priv && priv->size > 0) {
|
|
Packit Service |
f36a15 |
ret = tplg_add_data(tplg, elem, priv,
|
|
Packit Service |
f36a15 |
sizeof(*priv) + priv->size);
|
|
Packit Service |
f36a15 |
if (ret < 0)
|
|
Packit Service |
f36a15 |
return ret;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
/* decode pcm from the binary input */
|
|
Packit Service |
f36a15 |
int tplg_decode_pcm(snd_tplg_t *tplg,
|
|
Packit Service |
f36a15 |
size_t pos,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_hdr *hdr,
|
|
Packit Service |
f36a15 |
void *bin, size_t size)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_pcm *pcm;
|
|
Packit Service |
f36a15 |
snd_tplg_obj_template_t t;
|
|
Packit Service |
f36a15 |
struct snd_tplg_pcm_template *pt;
|
|
Packit Service |
f36a15 |
struct snd_tplg_stream_caps_template caps[2], *cap;
|
|
Packit Service |
f36a15 |
struct snd_tplg_stream_template *stream;
|
|
Packit Service |
f36a15 |
unsigned int i;
|
|
Packit Service |
f36a15 |
size_t asize;
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
err = tplg_decode_template(tplg, pos, hdr, &t);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
asize = sizeof(*pt) + SND_SOC_TPLG_STREAM_CONFIG_MAX * sizeof(*stream);
|
|
Packit Service |
f36a15 |
pt = alloca(asize);
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
next:
|
|
Packit Service |
f36a15 |
memset(pt, 0, asize);
|
|
Packit Service |
f36a15 |
pcm = bin;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (size < sizeof(*pcm)) {
|
|
Packit Service |
f36a15 |
SNDERR("pcm: small size %d", size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (sizeof(*pcm) != pcm->size) {
|
|
Packit Service |
f36a15 |
SNDERR("pcm: unknown element size %d (expected %zd)",
|
|
Packit Service |
f36a15 |
pcm->size, sizeof(*pcm));
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (pcm->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) {
|
|
Packit Service |
f36a15 |
SNDERR("pcm: wrong number of streams %d", pcm->num_streams);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (sizeof(*pcm) + pcm->priv.size > size) {
|
|
Packit Service |
f36a15 |
SNDERR("pcm: wrong private data size %d", pcm->priv.size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "pcm: size %d private size %d streams %d",
|
|
Packit Service |
f36a15 |
pcm->size, pcm->priv.size, pcm->num_streams);
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
pt->pcm_name = pcm->pcm_name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "pcm: pcm_name '%s'", pt->pcm_name);
|
|
Packit Service |
f36a15 |
pt->dai_name = pcm->dai_name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "pcm: dai_name '%s'", pt->dai_name);
|
|
Packit Service |
f36a15 |
pt->pcm_id = pcm->pcm_id;
|
|
Packit Service |
f36a15 |
pt->dai_id = pcm->dai_id;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "pcm: pcm_id %d dai_id %d", pt->pcm_id, pt->dai_id);
|
|
Packit Service |
f36a15 |
pt->playback = pcm->playback;
|
|
Packit Service |
f36a15 |
pt->capture = pcm->capture;
|
|
Packit Service |
f36a15 |
pt->compress = pcm->compress;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "pcm: playback %d capture %d compress",
|
|
Packit Service |
f36a15 |
pt->playback, pt->capture, pt->compress);
|
|
Packit Service |
f36a15 |
pt->num_streams = pcm->num_streams;
|
|
Packit Service |
f36a15 |
pt->flag_mask = pcm->flag_mask;
|
|
Packit Service |
f36a15 |
pt->flags = pcm->flags;
|
|
Packit Service |
f36a15 |
for (i = 0; i < pcm->num_streams; i++) {
|
|
Packit Service |
f36a15 |
stream = &pt->stream[i];
|
|
Packit Service |
f36a15 |
if (pcm->stream[i].size != sizeof(pcm->stream[0])) {
|
|
Packit Service |
f36a15 |
SNDERR("pcm: unknown stream structure size %d",
|
|
Packit Service |
f36a15 |
pcm->stream[i].size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit Service |
f36a15 |
stream->name = pcm->stream[i].name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, stream[i]),
|
|
Packit Service |
f36a15 |
"stream %d: '%s'", i, stream->name);
|
|
Packit Service |
f36a15 |
stream->format = pcm->stream[i].format;
|
|
Packit Service |
f36a15 |
stream->rate = pcm->stream[i].rate;
|
|
Packit Service |
f36a15 |
stream->period_bytes = pcm->stream[i].period_bytes;
|
|
Packit Service |
f36a15 |
stream->buffer_bytes = pcm->stream[i].buffer_bytes;
|
|
Packit Service |
f36a15 |
stream->channels = pcm->stream[i].channels;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
for (i = 0; i < 2; i++) {
|
|
Packit Service |
f36a15 |
if (i == 0 && !pcm->playback)
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
if (i == 1 && !pcm->capture)
|
|
Packit Service |
f36a15 |
continue;
|
|
Packit Service |
f36a15 |
cap = &caps[i];
|
|
Packit Service |
f36a15 |
pt->caps[i] = cap;
|
|
Packit Service |
f36a15 |
if (pcm->caps[i].size != sizeof(pcm->caps[0])) {
|
|
Packit Service |
f36a15 |
SNDERR("pcm: unknown caps structure size %d",
|
|
Packit Service |
f36a15 |
pcm->caps[i].size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
cap->name = pcm->caps[i].name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, caps[i]),
|
|
Packit Service |
f36a15 |
"caps %d: '%s'", i, cap->name);
|
|
Packit Service |
f36a15 |
cap->formats = pcm->caps[i].formats;
|
|
Packit Service |
f36a15 |
cap->rates = pcm->caps[i].rates;
|
|
Packit Service |
f36a15 |
cap->rate_min = pcm->caps[i].rate_min;
|
|
Packit Service |
f36a15 |
cap->rate_max = pcm->caps[i].rate_max;
|
|
Packit Service |
f36a15 |
cap->channels_min = pcm->caps[i].channels_min;
|
|
Packit Service |
f36a15 |
cap->channels_max = pcm->caps[i].channels_max;
|
|
Packit Service |
f36a15 |
cap->periods_min = pcm->caps[i].periods_min;
|
|
Packit Service |
f36a15 |
cap->periods_max = pcm->caps[i].periods_max;
|
|
Packit Service |
f36a15 |
cap->period_size_min = pcm->caps[i].period_size_min;
|
|
Packit Service |
f36a15 |
cap->period_size_max = pcm->caps[i].period_size_max;
|
|
Packit Service |
f36a15 |
cap->buffer_size_min = pcm->caps[i].buffer_size_min;
|
|
Packit Service |
f36a15 |
cap->buffer_size_max = pcm->caps[i].buffer_size_max;
|
|
Packit Service |
f36a15 |
cap->sig_bits = pcm->caps[i].sig_bits;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, priv),
|
|
Packit Service |
f36a15 |
"pcm: private start");
|
|
Packit Service |
f36a15 |
pt->priv = &pcm->priv;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
bin += sizeof(*pcm) + pcm->priv.size;
|
|
Packit Service |
f36a15 |
size -= sizeof(*pcm) + pcm->priv.size;
|
|
Packit Service |
f36a15 |
pos += sizeof(*pcm) + pcm->priv.size;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
t.pcm = pt;
|
|
Packit Service |
f36a15 |
err = snd_tplg_add_object(tplg, &t);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (size > 0)
|
|
Packit Service |
f36a15 |
goto next;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
return 0;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
/* decode dai from the binary input */
|
|
Packit Service |
f36a15 |
int tplg_decode_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
size_t pos ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
void *bin ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
size_t size ATTRIBUTE_UNUSED)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
SNDERR("not implemented");
|
|
Packit Service |
f36a15 |
return -ENXIO;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
/* decode cc from the binary input */
|
|
Packit Service |
f36a15 |
int tplg_decode_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
size_t pos ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
void *bin ATTRIBUTE_UNUSED,
|
|
Packit Service |
f36a15 |
size_t size ATTRIBUTE_UNUSED)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
SNDERR("not implemented");
|
|
Packit Service |
f36a15 |
return -ENXIO;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
/* decode link from the binary input */
|
|
Packit Service |
f36a15 |
int tplg_decode_link(snd_tplg_t *tplg,
|
|
Packit Service |
f36a15 |
size_t pos,
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_hdr *hdr,
|
|
Packit Service |
f36a15 |
void *bin, size_t size)
|
|
Packit Service |
f36a15 |
{
|
|
Packit Service |
f36a15 |
struct snd_soc_tplg_link_config *link;
|
|
Packit Service |
f36a15 |
snd_tplg_obj_template_t t;
|
|
Packit Service |
f36a15 |
struct snd_tplg_link_template lt;
|
|
Packit Service |
f36a15 |
struct snd_tplg_stream_template streams[SND_SOC_TPLG_STREAM_CONFIG_MAX];
|
|
Packit Service |
f36a15 |
struct snd_tplg_stream_template *stream;
|
|
Packit Service |
f36a15 |
struct snd_tplg_hw_config_template hws[SND_SOC_TPLG_HW_CONFIG_MAX];
|
|
Packit Service |
f36a15 |
struct snd_tplg_hw_config_template *hw;
|
|
Packit Service |
f36a15 |
unsigned int i, j;
|
|
Packit Service |
f36a15 |
int err;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
err = tplg_decode_template(tplg, pos, hdr, &t);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit |
4a16fb |
|
|
Packit Service |
f36a15 |
next:
|
|
Packit Service |
f36a15 |
memset(<, 0, sizeof(lt));
|
|
Packit Service |
f36a15 |
memset(streams, 0, sizeof(streams));
|
|
Packit Service |
f36a15 |
memset(hws, 0, sizeof(hws));
|
|
Packit Service |
f36a15 |
link = bin;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (size < sizeof(*link)) {
|
|
Packit Service |
f36a15 |
SNDERR("link: small size %d", size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit Service |
f36a15 |
if (sizeof(*link) != link->size) {
|
|
Packit Service |
f36a15 |
SNDERR("link: unknown element size %d (expected %zd)",
|
|
Packit Service |
f36a15 |
link->size, sizeof(*link));
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (link->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) {
|
|
Packit Service |
f36a15 |
SNDERR("link: wrong number of streams %d", link->num_streams);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (link->num_hw_configs > SND_SOC_TPLG_HW_CONFIG_MAX) {
|
|
Packit Service |
f36a15 |
SNDERR("link: wrong number of streams %d", link->num_streams);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
if (sizeof(*link) + link->priv.size > size) {
|
|
Packit Service |
f36a15 |
SNDERR("link: wrong private data size %d", link->priv.size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "link: size %d private size %d streams %d "
|
|
Packit Service |
f36a15 |
"hw_configs %d",
|
|
Packit Service |
f36a15 |
link->size, link->priv.size, link->num_streams,
|
|
Packit Service |
f36a15 |
link->num_hw_configs);
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
lt.id = link->id;
|
|
Packit Service |
f36a15 |
lt.name = link->name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "link: name '%s'", lt.name);
|
|
Packit Service |
f36a15 |
lt.stream_name = link->stream_name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos, "link: stream_name '%s'", lt.stream_name);
|
|
Packit Service |
f36a15 |
lt.num_streams = link->num_streams;
|
|
Packit Service |
f36a15 |
lt.num_hw_configs = link->num_hw_configs;
|
|
Packit Service |
f36a15 |
lt.default_hw_config_id = link->default_hw_config_id;
|
|
Packit Service |
f36a15 |
lt.flag_mask = link->flag_mask;
|
|
Packit Service |
f36a15 |
lt.flags = link->flags;
|
|
Packit Service |
f36a15 |
for (i = 0; i < link->num_streams; i++) {
|
|
Packit Service |
f36a15 |
stream = &streams[i];
|
|
Packit Service |
f36a15 |
if (link->stream[i].size != sizeof(link->stream[0])) {
|
|
Packit Service |
f36a15 |
SNDERR("link: unknown stream structure size %d",
|
|
Packit Service |
f36a15 |
link->stream[i].size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
stream->name = link->stream[i].name;
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D',
|
|
Packit Service |
f36a15 |
pos + offsetof(struct snd_soc_tplg_link_config, stream[i]),
|
|
Packit Service |
f36a15 |
"stream %d: '%s'", i, stream->name);
|
|
Packit Service |
f36a15 |
stream->format = link->stream[i].format;
|
|
Packit Service |
f36a15 |
stream->rate = link->stream[i].rate;
|
|
Packit Service |
f36a15 |
stream->period_bytes = link->stream[i].period_bytes;
|
|
Packit Service |
f36a15 |
stream->buffer_bytes = link->stream[i].buffer_bytes;
|
|
Packit Service |
f36a15 |
stream->channels = link->stream[i].channels;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
lt.stream = streams;
|
|
Packit Service |
f36a15 |
for (i = 0; i < link->num_hw_configs; i++) {
|
|
Packit Service |
f36a15 |
hw = &hws[i];
|
|
Packit Service |
f36a15 |
if (link->hw_config[i].size != sizeof(link->hw_config[0])) {
|
|
Packit Service |
f36a15 |
SNDERR("link: unknown hw_config structure size %d",
|
|
Packit Service |
f36a15 |
link->hw_config[i].size);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
hw->id = link->hw_config[i].id;
|
|
Packit Service |
f36a15 |
hw->fmt = link->hw_config[i].fmt;
|
|
Packit Service |
f36a15 |
hw->clock_gated = link->hw_config[i].clock_gated;
|
|
Packit Service |
f36a15 |
hw->invert_bclk = link->hw_config[i].invert_bclk;
|
|
Packit Service |
f36a15 |
hw->invert_fsync = link->hw_config[i].invert_fsync;
|
|
Packit Service |
f36a15 |
hw->bclk_master = link->hw_config[i].bclk_master;
|
|
Packit Service |
f36a15 |
hw->fsync_master = link->hw_config[i].fsync_master;
|
|
Packit Service |
f36a15 |
hw->mclk_direction = link->hw_config[i].mclk_direction;
|
|
Packit Service |
f36a15 |
hw->mclk_rate = link->hw_config[i].mclk_rate;
|
|
Packit Service |
f36a15 |
hw->bclk_rate = link->hw_config[i].bclk_rate;
|
|
Packit Service |
f36a15 |
hw->fsync_rate = link->hw_config[i].fsync_rate;
|
|
Packit Service |
f36a15 |
hw->tdm_slots = link->hw_config[i].tdm_slots;
|
|
Packit Service |
f36a15 |
hw->tdm_slot_width = link->hw_config[i].tdm_slot_width;
|
|
Packit Service |
f36a15 |
hw->tx_slots = link->hw_config[i].tx_slots;
|
|
Packit Service |
f36a15 |
hw->rx_slots = link->hw_config[i].rx_slots;
|
|
Packit Service |
f36a15 |
hw->tx_channels = link->hw_config[i].tx_channels;
|
|
Packit Service |
f36a15 |
if (hw->tx_channels > SND_SOC_TPLG_MAX_CHAN) {
|
|
Packit Service |
f36a15 |
SNDERR("link: wrong tx channels %d", hw->tx_channels);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
for (j = 0; j < hw->tx_channels; j++)
|
|
Packit Service |
f36a15 |
hw->tx_chanmap[j] = link->hw_config[i].tx_chanmap[j];
|
|
Packit Service |
f36a15 |
hw->rx_channels = link->hw_config[i].rx_channels;
|
|
Packit Service |
f36a15 |
if (hw->rx_channels > SND_SOC_TPLG_MAX_CHAN) {
|
|
Packit Service |
f36a15 |
SNDERR("link: wrong rx channels %d", hw->tx_channels);
|
|
Packit Service |
f36a15 |
return -EINVAL;
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
for (j = 0; j < hw->rx_channels; j++)
|
|
Packit Service |
f36a15 |
hw->rx_chanmap[j] = link->hw_config[i].rx_chanmap[j];
|
|
Packit Service |
f36a15 |
}
|
|
Packit Service |
f36a15 |
lt.hw_config = hws;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, priv),
|
|
Packit Service |
f36a15 |
"link: private start");
|
|
Packit Service |
f36a15 |
lt.priv = &link->priv;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
bin += sizeof(*link) + link->priv.size;
|
|
Packit Service |
f36a15 |
size -= sizeof(*link) + link->priv.size;
|
|
Packit Service |
f36a15 |
pos += sizeof(*link) + link->priv.size;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
t.link = <
|
|
Packit Service |
f36a15 |
err = snd_tplg_add_object(tplg, &t);
|
|
Packit Service |
f36a15 |
if (err < 0)
|
|
Packit Service |
f36a15 |
return err;
|
|
Packit Service |
f36a15 |
|
|
Packit Service |
f36a15 |
if (size > 0)
|
|
Packit Service |
f36a15 |
goto next;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|