/* Copyright(c) 2014-2015 Intel Corporation All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. Authors: Mengdong Lin Yao Jin Liam Girdwood */ #include "list.h" #include "tplg_local.h" /* mapping of channel text names to types */ static const struct map_elem channel_map[] = { {"mono", SNDRV_CHMAP_MONO}, /* mono stream */ {"fl", SNDRV_CHMAP_FL}, /* front left */ {"fr", SNDRV_CHMAP_FR}, /* front right */ {"rl", SNDRV_CHMAP_RL}, /* rear left */ {"rr", SNDRV_CHMAP_RR}, /* rear right */ {"fc", SNDRV_CHMAP_FC}, /* front center */ {"lfe", SNDRV_CHMAP_LFE}, /* LFE */ {"sl", SNDRV_CHMAP_SL}, /* side left */ {"sr", SNDRV_CHMAP_SR}, /* side right */ {"rc", SNDRV_CHMAP_RC}, /* rear center */ {"flc", SNDRV_CHMAP_FLC}, /* front left center */ {"frc", SNDRV_CHMAP_FRC}, /* front right center */ {"rlc", SNDRV_CHMAP_RLC}, /* rear left center */ {"rrc", SNDRV_CHMAP_RRC}, /* rear right center */ {"flw", SNDRV_CHMAP_FLW}, /* front left wide */ {"frw", SNDRV_CHMAP_FRW}, /* front right wide */ {"flh", SNDRV_CHMAP_FLH}, /* front left high */ {"fch", SNDRV_CHMAP_FCH}, /* front center high */ {"frh", SNDRV_CHMAP_FRH}, /* front right high */ {"tc", SNDRV_CHMAP_TC}, /* top center */ {"tfl", SNDRV_CHMAP_TFL}, /* top front left */ {"tfr", SNDRV_CHMAP_TFR}, /* top front right */ {"tfc", SNDRV_CHMAP_TFC}, /* top front center */ {"trl", SNDRV_CHMAP_TRL}, /* top rear left */ {"trr", SNDRV_CHMAP_TRR}, /* top rear right */ {"trc", SNDRV_CHMAP_TRC}, /* top rear center */ {"tflc", SNDRV_CHMAP_TFLC}, /* top front left center */ {"tfrc", SNDRV_CHMAP_TFRC}, /* top front right center */ {"tsl", SNDRV_CHMAP_TSL}, /* top side left */ {"tsr", SNDRV_CHMAP_TSR}, /* top side right */ {"llfe", SNDRV_CHMAP_LLFE}, /* left LFE */ {"rlfe", SNDRV_CHMAP_RLFE}, /* right LFE */ {"bc", SNDRV_CHMAP_BC}, /* bottom center */ {"blc", SNDRV_CHMAP_BLC}, /* bottom left center */ {"brc", SNDRV_CHMAP_BRC}, /* bottom right center */ }; static int lookup_channel(const char *c) { unsigned int i; for (i = 0; i < ARRAY_SIZE(channel_map); i++) { if (strcasecmp(channel_map[i].name, c) == 0) { return channel_map[i].id; } } return -EINVAL; } const char *tplg_channel_name(int type) { unsigned int i; for (i = 0; i < ARRAY_SIZE(channel_map); i++) { if (channel_map[i].id == type) return channel_map[i].name; } return NULL; } /* Parse a channel mapping. */ int tplg_parse_channel(snd_tplg_t *tplg, snd_config_t *cfg, void *private) { snd_config_iterator_t i, next; snd_config_t *n; struct snd_soc_tplg_channel *channel = private; const char *id; int channel_id, value; if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN) return -EINVAL; channel += tplg->channel_idx; snd_config_get_id(cfg, &id); tplg_dbg("\tChannel %s at index %d", id, tplg->channel_idx); channel_id = lookup_channel(id); if (channel_id < 0) { SNDERR("invalid channel %s", id); return -EINVAL; } channel->id = channel_id; channel->size = sizeof(*channel); tplg_dbg("\tChan %s = %d", id, channel->id); snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); /* get id */ if (snd_config_get_id(n, &id) < 0) continue; /* get value */ if (tplg_get_integer(n, &value, 0) < 0) continue; if (strcmp(id, "reg") == 0) channel->reg = value; else if (strcmp(id, "shift") == 0) channel->shift = value; tplg_dbg("\t\t%s = %d", id, value); } tplg->channel_idx++; return 0; } int tplg_save_channels(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct snd_soc_tplg_channel *channel, unsigned int count, struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_channel *c; const char *s; unsigned int index; int err; if (count == 0) return 0; err = tplg_save_printf(dst, pfx, "channel {\n"); for (index = 0; err >= 0 && index < count; index++) { c = channel + index; s = tplg_channel_name(c->id); if (s == NULL) err = tplg_save_printf(dst, pfx, "\t%u", c->id); else err = tplg_save_printf(dst, pfx, "\t%s", s); if (err >= 0) err = tplg_save_printf(dst, NULL, " {\n"); if (err >= 0) err = tplg_save_printf(dst, pfx, "\t\treg %d\n", c->reg); if (err >= 0 && c->shift > 0) err = tplg_save_printf(dst, pfx, "\t\tshift %u\n", c->shift); if (err >= 0) err = tplg_save_printf(dst, pfx, "\t}\n"); } if (err >= 0) err = tplg_save_printf(dst, pfx, "}\n"); return err; }