mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
ASoC: Intel: avs: Conditional path support
Merge series from Cezary Rojewski <cezary.rojewski@intel.com>: The code presented here is a lighter version of what was initially discussed in 2021 [1]. Later, we've had a more general discussion [2] "what if the feature was part of the ASoC core instead?". The discussion turned towards leaving a simplified version within the avs/, so here is the final outcome. What's removed when compared to the older [1] version? - conditional path priorities - conditional path overriding The background: Conditional path (condpath) helps facilitate modern audio usecases such as Echo Cancellations and Noise Reduction. These are not invoked by the means of userspace application opening an endpoint (FrontEnd) but are a "side effect" of selected PCMs running simultaneously e.g.: if both Speaker (source) and Microphone Array (sink) are running, reference data from the Speaker and take it into account when processing capture for better voice command detection ratio. Which PCMs are needed for given conditional path to be spawned is determinated by the driver when registering the condpath. Two patches implement the feature: 1) update the topology parser to acknowledge the new tuples 2) update the path-creation and functions that participate in the PCM-runtime e.g.: run/pause. The runtime update is needed to keep streaming sane - all the path operations shall be synchronized when a condpath is being spawned or its status is about to change. [1]: https://lore.kernel.org/alsa-devel/20211208111301.1817725-21-cezary.rojewski@intel.com/ [2]: https://lore.kernel.org/linux-sound/20240821101816.1494541-1-cezary.rojewski@intel.com/
This commit is contained in:
commit
e896f262b3
|
|
@ -133,6 +133,21 @@ enum avs_tplg_token {
|
|||
AVS_TKN_PATH_FE_FMT_ID_U32 = 1902,
|
||||
AVS_TKN_PATH_BE_FMT_ID_U32 = 1903,
|
||||
|
||||
/* struct avs_tplg_path_template (conditional) */
|
||||
AVS_TKN_CONDPATH_TMPL_ID_U32 = 1801,
|
||||
AVS_TKN_CONDPATH_TMPL_SOURCE_TPLG_NAME_STRING = 2002,
|
||||
AVS_TKN_CONDPATH_TMPL_SOURCE_PATH_TMPL_ID_U32 = 2003,
|
||||
AVS_TKN_CONDPATH_TMPL_SINK_TPLG_NAME_STRING = 2004,
|
||||
AVS_TKN_CONDPATH_TMPL_SINK_PATH_TMPL_ID_U32 = 2005,
|
||||
AVS_TKN_CONDPATH_TMPL_COND_TYPE_U32 = 2006,
|
||||
AVS_TKN_CONDPATH_TMPL_OVERRIDABLE_BOOL = 2007,
|
||||
AVS_TKN_CONDPATH_TMPL_PRIORITY_U8 = 2008,
|
||||
|
||||
/* struct avs_tplg_path (conditional) */
|
||||
AVS_TKN_CONDPATH_ID_U32 = 1901,
|
||||
AVS_TKN_CONDPATH_SOURCE_PATH_ID_U32 = 2102,
|
||||
AVS_TKN_CONDPATH_SINK_PATH_ID_U32 = 2103,
|
||||
|
||||
/* struct avs_tplg_pin_format */
|
||||
AVS_TKN_PIN_FMT_INDEX_U32 = 2201,
|
||||
AVS_TKN_PIN_FMT_IOBS_U32 = 2202,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,55 @@ avs_path_find_variant(struct avs_dev *adev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct avs_tplg_path *avs_condpath_find_variant(struct avs_dev *adev,
|
||||
struct avs_tplg_path_template *template,
|
||||
struct avs_path *source,
|
||||
struct avs_path *sink)
|
||||
{
|
||||
struct avs_tplg_path *variant;
|
||||
|
||||
list_for_each_entry(variant, &template->path_list, node) {
|
||||
if (variant->source_path_id == source->template->id &&
|
||||
variant->sink_path_id == sink->template->id)
|
||||
return variant;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool avs_tplg_path_template_id_equal(struct avs_tplg_path_template_id *id,
|
||||
struct avs_tplg_path_template_id *id2)
|
||||
{
|
||||
return id->id == id2->id && !strcmp(id->tplg_name, id2->tplg_name);
|
||||
}
|
||||
|
||||
static struct avs_path *avs_condpath_find_match(struct avs_dev *adev,
|
||||
struct avs_tplg_path_template *template,
|
||||
struct avs_path *path, int dir)
|
||||
{
|
||||
struct avs_tplg_path_template_id *id, *id2;
|
||||
|
||||
if (dir) {
|
||||
id = &template->source;
|
||||
id2 = &template->sink;
|
||||
} else {
|
||||
id = &template->sink;
|
||||
id2 = &template->source;
|
||||
}
|
||||
|
||||
/* Check whether this path is either source or sink of condpath template. */
|
||||
if (id->id != path->template->owner->id ||
|
||||
strcmp(id->tplg_name, path->template->owner->owner->name))
|
||||
return NULL;
|
||||
|
||||
/* Unidirectional condpaths are allowed. */
|
||||
if (avs_tplg_path_template_id_equal(id, id2))
|
||||
return path;
|
||||
|
||||
/* Now find the counterpart. */
|
||||
return avs_path_find_path(adev, id2->tplg_name, id2->id);
|
||||
}
|
||||
|
||||
static struct acpi_nhlt_config *
|
||||
avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t);
|
||||
|
||||
|
|
@ -1051,6 +1100,10 @@ static int avs_path_init(struct avs_dev *adev, struct avs_path *path,
|
|||
path->dma_id = dma_id;
|
||||
INIT_LIST_HEAD(&path->ppl_list);
|
||||
INIT_LIST_HEAD(&path->node);
|
||||
INIT_LIST_HEAD(&path->source_list);
|
||||
INIT_LIST_HEAD(&path->sink_list);
|
||||
INIT_LIST_HEAD(&path->source_node);
|
||||
INIT_LIST_HEAD(&path->sink_node);
|
||||
|
||||
/* create all the pipelines */
|
||||
list_for_each_entry(tppl, &template->ppl_list, node) {
|
||||
|
|
@ -1134,12 +1187,129 @@ static struct avs_path *avs_path_create_unlocked(struct avs_dev *adev, u32 dma_i
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void avs_condpath_free(struct avs_dev *adev, struct avs_path *path)
|
||||
{
|
||||
int ret;
|
||||
|
||||
list_del(&path->source_node);
|
||||
list_del(&path->sink_node);
|
||||
|
||||
ret = avs_path_reset(path);
|
||||
if (ret < 0)
|
||||
dev_err(adev->dev, "reset condpath failed: %d\n", ret);
|
||||
|
||||
ret = avs_path_unbind(path);
|
||||
if (ret < 0)
|
||||
dev_err(adev->dev, "unbind condpath failed: %d\n", ret);
|
||||
|
||||
avs_path_free_unlocked(path);
|
||||
}
|
||||
|
||||
static struct avs_path *avs_condpath_create(struct avs_dev *adev,
|
||||
struct avs_tplg_path *template,
|
||||
struct avs_path *source,
|
||||
struct avs_path *sink)
|
||||
{
|
||||
struct avs_path *path;
|
||||
int ret;
|
||||
|
||||
path = avs_path_create_unlocked(adev, 0, template);
|
||||
if (IS_ERR(path))
|
||||
return path;
|
||||
|
||||
ret = avs_path_bind(path);
|
||||
if (ret)
|
||||
goto err_bind;
|
||||
|
||||
ret = avs_path_reset(path);
|
||||
if (ret)
|
||||
goto err_reset;
|
||||
|
||||
path->source = source;
|
||||
path->sink = sink;
|
||||
list_add_tail(&path->source_node, &source->source_list);
|
||||
list_add_tail(&path->sink_node, &sink->sink_list);
|
||||
|
||||
return path;
|
||||
|
||||
err_reset:
|
||||
avs_path_unbind(path);
|
||||
err_bind:
|
||||
avs_path_free_unlocked(path);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int avs_condpaths_walk(struct avs_dev *adev, struct avs_path *path, int dir)
|
||||
{
|
||||
struct avs_soc_component *acomp;
|
||||
struct avs_path *source, *sink;
|
||||
struct avs_path **other;
|
||||
|
||||
if (dir) {
|
||||
source = path;
|
||||
other = &sink;
|
||||
} else {
|
||||
sink = path;
|
||||
other = &source;
|
||||
}
|
||||
|
||||
list_for_each_entry(acomp, &adev->comp_list, node) {
|
||||
for (int i = 0; i < acomp->tplg->num_condpath_tmpls; i++) {
|
||||
struct avs_tplg_path_template *template;
|
||||
struct avs_tplg_path *variant;
|
||||
struct avs_path *cpath;
|
||||
|
||||
template = &acomp->tplg->condpath_tmpls[i];
|
||||
|
||||
/* Do not create unidirectional condpaths twice. */
|
||||
if (avs_tplg_path_template_id_equal(&template->source,
|
||||
&template->sink) && dir)
|
||||
continue;
|
||||
|
||||
*other = avs_condpath_find_match(adev, template, path, dir);
|
||||
if (!*other)
|
||||
continue;
|
||||
|
||||
variant = avs_condpath_find_variant(adev, template, source, sink);
|
||||
if (!variant)
|
||||
continue;
|
||||
|
||||
cpath = avs_condpath_create(adev, variant, source, sink);
|
||||
if (IS_ERR(cpath))
|
||||
return PTR_ERR(cpath);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Caller responsible for holding adev->path_mutex. */
|
||||
static int avs_condpaths_walk_all(struct avs_dev *adev, struct avs_path *path)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
}
|
||||
|
||||
void avs_path_free(struct avs_path *path)
|
||||
{
|
||||
struct avs_path *cpath, *csave;
|
||||
struct avs_dev *adev = path->owner;
|
||||
|
||||
mutex_lock(&adev->path_mutex);
|
||||
|
||||
/* Free all condpaths this path spawned. */
|
||||
list_for_each_entry_safe(cpath, csave, &path->source_list, source_node)
|
||||
avs_condpath_free(path->owner, cpath);
|
||||
list_for_each_entry_safe(cpath, csave, &path->sink_list, sink_node)
|
||||
avs_condpath_free(path->owner, cpath);
|
||||
|
||||
avs_path_free_unlocked(path);
|
||||
|
||||
mutex_unlock(&adev->path_mutex);
|
||||
}
|
||||
|
||||
|
|
@ -1150,6 +1320,7 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
|
|||
{
|
||||
struct avs_tplg_path *variant;
|
||||
struct avs_path *path;
|
||||
int ret;
|
||||
|
||||
variant = avs_path_find_variant(adev, template, fe_params, be_params);
|
||||
if (!variant) {
|
||||
|
|
@ -1163,7 +1334,16 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
|
|||
mutex_lock(&adev->comp_list_mutex);
|
||||
|
||||
path = avs_path_create_unlocked(adev, dma_id, variant);
|
||||
if (IS_ERR(path))
|
||||
goto exit;
|
||||
|
||||
ret = avs_condpaths_walk_all(adev, path);
|
||||
if (ret) {
|
||||
avs_path_free_unlocked(path);
|
||||
path = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&adev->comp_list_mutex);
|
||||
mutex_unlock(&adev->path_mutex);
|
||||
|
||||
|
|
@ -1286,6 +1466,42 @@ int avs_path_reset(struct avs_path *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int avs_condpath_pause(struct avs_dev *adev, struct avs_path *cpath)
|
||||
{
|
||||
struct avs_path_pipeline *ppl;
|
||||
int ret;
|
||||
|
||||
if (cpath->state == AVS_PPL_STATE_PAUSED)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry_reverse(ppl, &cpath->ppl_list, node) {
|
||||
ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_PAUSED);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "pause cpath failed: %d\n", ret);
|
||||
cpath->state = AVS_PPL_STATE_INVALID;
|
||||
return AVS_IPC_RET(ret);
|
||||
}
|
||||
}
|
||||
|
||||
cpath->state = AVS_PPL_STATE_PAUSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path)
|
||||
{
|
||||
struct avs_path *cpath;
|
||||
|
||||
mutex_lock(&adev->path_mutex);
|
||||
|
||||
/* If either source or sink stops, so do the attached conditional paths. */
|
||||
list_for_each_entry(cpath, &path->source_list, source_node)
|
||||
avs_condpath_pause(adev, cpath);
|
||||
list_for_each_entry(cpath, &path->sink_list, sink_node)
|
||||
avs_condpath_pause(adev, cpath);
|
||||
|
||||
mutex_unlock(&adev->path_mutex);
|
||||
}
|
||||
|
||||
int avs_path_pause(struct avs_path *path)
|
||||
{
|
||||
struct avs_path_pipeline *ppl;
|
||||
|
|
@ -1295,6 +1511,8 @@ int avs_path_pause(struct avs_path *path)
|
|||
if (path->state == AVS_PPL_STATE_PAUSED)
|
||||
return 0;
|
||||
|
||||
avs_condpaths_pause(adev, path);
|
||||
|
||||
list_for_each_entry_reverse(ppl, &path->ppl_list, node) {
|
||||
ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id,
|
||||
AVS_PPL_STATE_PAUSED);
|
||||
|
|
@ -1309,6 +1527,50 @@ int avs_path_pause(struct avs_path *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int avs_condpath_run(struct avs_dev *adev, struct avs_path *cpath, int trigger)
|
||||
{
|
||||
struct avs_path_pipeline *ppl;
|
||||
int ret;
|
||||
|
||||
if (cpath->state == AVS_PPL_STATE_RUNNING)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(ppl, &cpath->ppl_list, node) {
|
||||
if (ppl->template->cfg->trigger != trigger)
|
||||
continue;
|
||||
|
||||
ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_RUNNING);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "run cpath failed: %d\n", ret);
|
||||
cpath->state = AVS_PPL_STATE_INVALID;
|
||||
return AVS_IPC_RET(ret);
|
||||
}
|
||||
}
|
||||
|
||||
cpath->state = AVS_PPL_STATE_RUNNING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int trigger)
|
||||
{
|
||||
struct avs_path *cpath;
|
||||
|
||||
mutex_lock(&adev->path_mutex);
|
||||
|
||||
/* Run conditional paths only if source and sink are both running. */
|
||||
list_for_each_entry(cpath, &path->source_list, source_node)
|
||||
if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
|
||||
cpath->sink->state == AVS_PPL_STATE_RUNNING)
|
||||
avs_condpath_run(adev, cpath, trigger);
|
||||
|
||||
list_for_each_entry(cpath, &path->sink_list, sink_node)
|
||||
if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
|
||||
cpath->sink->state == AVS_PPL_STATE_RUNNING)
|
||||
avs_condpath_run(adev, cpath, trigger);
|
||||
|
||||
mutex_unlock(&adev->path_mutex);
|
||||
}
|
||||
|
||||
int avs_path_run(struct avs_path *path, int trigger)
|
||||
{
|
||||
struct avs_path_pipeline *ppl;
|
||||
|
|
@ -1332,5 +1594,10 @@ int avs_path_run(struct avs_path *path, int trigger)
|
|||
}
|
||||
|
||||
path->state = AVS_PPL_STATE_RUNNING;
|
||||
|
||||
/* Granular pipeline triggering not intended for conditional paths. */
|
||||
if (trigger == AVS_TPLG_TRIGGER_AUTO)
|
||||
avs_condpaths_run(adev, path, trigger);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,24 @@
|
|||
#include "avs.h"
|
||||
#include "topology.h"
|
||||
|
||||
#define AVS_COND_TYPE_NONE 0
|
||||
#define AVS_COND_TYPE_AECREF 1
|
||||
|
||||
struct avs_path {
|
||||
u32 dma_id;
|
||||
struct list_head ppl_list;
|
||||
u32 state;
|
||||
|
||||
/* condpath navigation for standard paths */
|
||||
struct list_head source_list;
|
||||
struct list_head sink_list;
|
||||
|
||||
/* conditional path fields */
|
||||
struct avs_path *source;
|
||||
struct avs_path *sink;
|
||||
struct list_head source_node;
|
||||
struct list_head sink_node;
|
||||
|
||||
struct avs_tplg_path *template;
|
||||
struct avs_dev *owner;
|
||||
/* device path management */
|
||||
|
|
|
|||
|
|
@ -1387,6 +1387,27 @@ static const struct avs_tplg_token_parser path_parsers[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct avs_tplg_token_parser condpath_parsers[] = {
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_ID_U32,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
|
||||
.offset = offsetof(struct avs_tplg_path, id),
|
||||
.parse = avs_parse_word_token,
|
||||
},
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_SOURCE_PATH_ID_U32,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
|
||||
.offset = offsetof(struct avs_tplg_path, source_path_id),
|
||||
.parse = avs_parse_word_token,
|
||||
},
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_SINK_PATH_ID_U32,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
|
||||
.offset = offsetof(struct avs_tplg_path, sink_path_id),
|
||||
.parse = avs_parse_word_token,
|
||||
},
|
||||
};
|
||||
|
||||
static struct avs_tplg_path *
|
||||
avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner,
|
||||
struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
|
||||
|
|
@ -1454,6 +1475,39 @@ static const struct avs_tplg_token_parser path_tmpl_parsers[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct avs_tplg_token_parser condpath_tmpl_parsers[] = {
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_TMPL_ID_U32,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
|
||||
.offset = offsetof(struct avs_tplg_path_template, id),
|
||||
.parse = avs_parse_word_token,
|
||||
},
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_TMPL_SOURCE_TPLG_NAME_STRING,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
|
||||
.offset = offsetof(struct avs_tplg_path_template, source.tplg_name),
|
||||
.parse = avs_parse_string_token,
|
||||
},
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_TMPL_SOURCE_PATH_TMPL_ID_U32,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
|
||||
.offset = offsetof(struct avs_tplg_path_template, source.id),
|
||||
.parse = avs_parse_word_token,
|
||||
},
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_TMPL_SINK_TPLG_NAME_STRING,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
|
||||
.offset = offsetof(struct avs_tplg_path_template, sink.tplg_name),
|
||||
.parse = avs_parse_string_token,
|
||||
},
|
||||
{
|
||||
.token = AVS_TKN_CONDPATH_TMPL_SINK_PATH_TMPL_ID_U32,
|
||||
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
|
||||
.offset = offsetof(struct avs_tplg_path_template, sink.id),
|
||||
.parse = avs_parse_word_token,
|
||||
},
|
||||
};
|
||||
|
||||
static int parse_path_template(struct snd_soc_component *comp,
|
||||
struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
|
||||
struct avs_tplg_path_template *template,
|
||||
|
|
@ -1524,6 +1578,56 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o
|
|||
return template;
|
||||
}
|
||||
|
||||
static int avs_tplg_parse_condpath_templates(struct snd_soc_component *comp,
|
||||
struct snd_soc_tplg_vendor_array *tuples,
|
||||
u32 block_size)
|
||||
{
|
||||
struct avs_soc_component *acomp = to_avs_soc_component(comp);
|
||||
struct avs_tplg *tplg = acomp->tplg;
|
||||
int ret, i;
|
||||
|
||||
ret = parse_dictionary_header(comp, tuples, (void **)&tplg->condpath_tmpls,
|
||||
&tplg->num_condpath_tmpls,
|
||||
sizeof(*tplg->condpath_tmpls),
|
||||
AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
block_size -= le32_to_cpu(tuples->size);
|
||||
/* With header parsed, move on to parsing entries. */
|
||||
tuples = avs_tplg_vendor_array_next(tuples);
|
||||
|
||||
for (i = 0; i < tplg->num_condpath_tmpls; i++) {
|
||||
struct avs_tplg_path_template *template;
|
||||
u32 esize;
|
||||
|
||||
template = &tplg->condpath_tmpls[i];
|
||||
template->owner = tplg; /* Used when building sysfs hierarchy. */
|
||||
INIT_LIST_HEAD(&template->path_list);
|
||||
INIT_LIST_HEAD(&template->node);
|
||||
|
||||
ret = avs_tplg_vendor_entry_size(tuples, block_size,
|
||||
AVS_TKN_CONDPATH_TMPL_ID_U32, &esize);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = parse_path_template(comp, tuples, esize, template,
|
||||
condpath_tmpl_parsers,
|
||||
ARRAY_SIZE(condpath_tmpl_parsers),
|
||||
condpath_parsers,
|
||||
ARRAY_SIZE(condpath_parsers));
|
||||
if (ret < 0) {
|
||||
dev_err(comp->dev, "parse condpath_tmpl: %d failed: %d\n", i, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
block_size -= esize;
|
||||
tuples = avs_tplg_vendor_array_at(tuples, esize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct avs_tplg_token_parser mod_init_config_parsers[] = {
|
||||
{
|
||||
.token = AVS_TKN_INIT_CONFIG_ID_U32,
|
||||
|
|
@ -1891,6 +1995,12 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Condpaths dictionary. */
|
||||
ret = avs_tplg_parse_condpath_templates(comp, tuples,
|
||||
has_init_config ? offset : remaining);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!has_init_config)
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ struct avs_tplg {
|
|||
u32 num_pplcfgs;
|
||||
struct avs_tplg_binding *bindings;
|
||||
u32 num_bindings;
|
||||
struct avs_tplg_path_template *condpath_tmpls;
|
||||
u32 num_condpath_tmpls;
|
||||
struct avs_tplg_init_config *init_configs;
|
||||
u32 num_init_configs;
|
||||
|
|
@ -155,6 +156,10 @@ struct avs_tplg_path_template {
|
|||
|
||||
struct snd_soc_dapm_widget *w;
|
||||
|
||||
/* Conditional path. */
|
||||
struct avs_tplg_path_template_id source;
|
||||
struct avs_tplg_path_template_id sink;
|
||||
|
||||
struct list_head path_list;
|
||||
|
||||
struct avs_tplg *owner;
|
||||
|
|
@ -176,6 +181,9 @@ struct avs_tplg_path {
|
|||
/* Path format requirements. */
|
||||
struct avs_audio_format *fe_fmt;
|
||||
struct avs_audio_format *be_fmt;
|
||||
/* Condpath path-variant requirements. */
|
||||
u32 source_path_id;
|
||||
u32 sink_path_id;
|
||||
|
||||
struct list_head ppl_list;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user