Blame src/topology/elem.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
int tplg_ref_add(struct tplg_elem *elem, int type, const char* id)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_ref *ref;
Packit 4a16fb
Packit 4a16fb
	ref = calloc(1, sizeof(*ref));
Packit 4a16fb
	if (!ref)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	strncpy(ref->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	ref->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
Packit 4a16fb
	ref->type = type;
Packit 4a16fb
Packit 4a16fb
	list_add_tail(&ref->list, &elem->ref_list);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* directly add a reference elem */
Packit 4a16fb
int tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_ref *ref;
Packit 4a16fb
Packit 4a16fb
	ref = calloc(1, sizeof(*ref));
Packit 4a16fb
	if (!ref)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	ref->type = elem_ref->type;
Packit 4a16fb
	ref->elem = elem_ref;
Packit 4a16fb
	snd_strlcpy(ref->id, elem_ref->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
Packit 4a16fb
	list_add_tail(&ref->list, &elem->ref_list);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void tplg_ref_free_list(struct list_head *base)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *pos, *npos;
Packit 4a16fb
	struct tplg_ref *ref;
Packit 4a16fb
Packit 4a16fb
	list_for_each_safe(pos, npos, base) {
Packit 4a16fb
		ref = list_entry(pos, struct tplg_ref, list);
Packit 4a16fb
		list_del(&ref->list);
Packit 4a16fb
		free(ref);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
struct tplg_elem *tplg_elem_new(void)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
Packit 4a16fb
	elem = calloc(1, sizeof(*elem));
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return NULL;
Packit 4a16fb
Packit 4a16fb
	INIT_LIST_HEAD(&elem->ref_list);
Packit 4a16fb
	return elem;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void tplg_elem_free(struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	tplg_ref_free_list(&elem->ref_list);
Packit 4a16fb
Packit 4a16fb
	/* free struct snd_tplg_ object,
Packit 4a16fb
	 * the union pointers share the same address
Packit 4a16fb
	 */
Packit 4a16fb
	if (elem->obj) {
Packit 4a16fb
		if (elem->free)
Packit 4a16fb
			elem->free(elem->obj);
Packit 4a16fb
Packit 4a16fb
		free(elem->obj);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	free(elem);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void tplg_elem_free_list(struct list_head *base)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *pos, *npos;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
Packit 4a16fb
	list_for_each_safe(pos, npos, base) {
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
		list_del(&elem->list);
Packit 4a16fb
		tplg_elem_free(elem);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id,
Packit 4a16fb
	unsigned int type, int index)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *pos;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
Packit 4a16fb
	if (!base || !id)
Packit 4a16fb
		return NULL;
Packit 4a16fb
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
Packit 4a16fb
		if (!strcmp(elem->id, id) && elem->type == type)
Packit 4a16fb
			return elem;
Packit 4a16fb
		/* SND_TPLG_INDEX_ALL is the default value "0" and applicable
Packit 4a16fb
		   for all use cases */
Packit 4a16fb
		if ((index != SND_TPLG_INDEX_ALL)
Packit 4a16fb
			&& (elem->index > index))
Packit 4a16fb
			break;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return NULL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* insert a new element into list in the ascending order of index value*/
Packit 4a16fb
static void tplg_elem_insert(struct tplg_elem *elem_p, struct list_head *list)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *pos, *p = &(elem_p->list);
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
Packit 4a16fb
	list_for_each(pos, list) {
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
		if (elem_p->index < elem->index)
Packit 4a16fb
			break;
Packit 4a16fb
	}
Packit 4a16fb
	p->prev = pos->prev;
Packit 4a16fb
	pos->prev->next = p;
Packit 4a16fb
	pos->prev = p;
Packit 4a16fb
	p->next = pos;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* create a new common element and object */
Packit 4a16fb
struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
Packit 4a16fb
	snd_config_t *cfg, const char *name, enum snd_tplg_type type)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	const char *id, *val = NULL;
Packit 4a16fb
	int obj_size = 0;
Packit 4a16fb
	void *obj;
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
Packit 4a16fb
	if (!cfg && !name)
Packit 4a16fb
		return NULL;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new();
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return NULL;
Packit 4a16fb
Packit 4a16fb
	/* do we get name from cfg */
Packit 4a16fb
	if (cfg) {
Packit 4a16fb
		snd_config_get_id(cfg, &id;;
Packit 4a16fb
		snd_strlcpy(elem->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
		elem->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
Packit 4a16fb
		/* as we insert new elem based on the index value, move index
Packit 4a16fb
		   parsing here */
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))
Packit 4a16fb
				continue;
Packit 4a16fb
			if (strcmp(id, "index") == 0) {
Packit 4a16fb
				if (snd_config_get_string(n, &val) < 0) {
Packit 4a16fb
					free(elem);
Packit 4a16fb
					return NULL;
Packit 4a16fb
				}
Packit 4a16fb
				elem->index = atoi(val);
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	} else if (name != NULL)
Packit 4a16fb
		snd_strlcpy(elem->id, name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
Packit 4a16fb
	switch (type) {
Packit 4a16fb
	case SND_TPLG_TYPE_DATA:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->pdata_list);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_MANIFEST:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->manifest_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_manifest);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_TEXT:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->text_list);
Packit 4a16fb
		obj_size = sizeof(struct tplg_texts);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_TLV:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->tlv_list);
Packit 4a16fb
		elem->size = sizeof(struct snd_soc_tplg_ctl_tlv);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_BYTES:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->bytes_ext_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_bytes_control);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_ENUM:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->enum_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_enum_control);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_MIXER:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->mixer_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_mixer_control);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_DAPM_WIDGET:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->widget_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_dapm_widget);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_STREAM_CONFIG:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->pcm_config_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_stream);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_STREAM_CAPS:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->pcm_caps_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_stream_caps);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_PCM:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->pcm_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_pcm);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_DAI:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->dai_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_dai);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_BE:
Packit 4a16fb
	case SND_TPLG_TYPE_LINK:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->be_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_link_config);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_CC:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->cc_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_link_config);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_TOKEN:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->token_list);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_TUPLE:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->tuple_list);
Packit 4a16fb
		elem->free = tplg_free_tuples;
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_TPLG_TYPE_HW_CONFIG:
Packit 4a16fb
		tplg_elem_insert(elem, &tplg->hw_cfg_list);
Packit 4a16fb
		obj_size = sizeof(struct snd_soc_tplg_hw_config);
Packit 4a16fb
		break;
Packit 4a16fb
	default:
Packit 4a16fb
		free(elem);
Packit 4a16fb
		return NULL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* create new object too if required */
Packit 4a16fb
	if (obj_size > 0) {
Packit 4a16fb
		obj = calloc(1, obj_size);
Packit 4a16fb
		if (obj == NULL) {
Packit 4a16fb
			free(elem);
Packit 4a16fb
			return NULL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		elem->obj = obj;
Packit 4a16fb
		elem->size = obj_size;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	elem->type = type;
Packit 4a16fb
	return elem;
Packit 4a16fb
}