Blame src/topology/pcm.c

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(&lt, 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
}