1 /*
2   Copyright(c) 2014-2015 Intel Corporation
3   All rights reserved.
4 
5   This library is free software; you can redistribute it and/or modify
6   it under the terms of the GNU Lesser General Public License as
7   published by the Free Software Foundation; either version 2.1 of
8   the License, or (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Lesser General Public License for more details.
14 
15   Authors: Mengdong Lin <mengdong.lin@intel.com>
16            Yao Jin <yao.jin@intel.com>
17            Liam Girdwood <liam.r.girdwood@linux.intel.com>
18 */
19 
20 #include "tplg_local.h"
21 
22 /* mapping of channel text names to types */
23 static const struct map_elem channel_map[] = {
24 	{"mono", SNDRV_CHMAP_MONO},	/* mono stream */
25 	{"fl", SNDRV_CHMAP_FL},		/* front left */
26 	{"fr", SNDRV_CHMAP_FR},		/* front right */
27 	{"rl", SNDRV_CHMAP_RL},		/* rear left */
28 	{"rr", SNDRV_CHMAP_RR},		/* rear right */
29 	{"fc", SNDRV_CHMAP_FC},		/* front center */
30 	{"lfe", SNDRV_CHMAP_LFE},	/* LFE */
31 	{"sl", SNDRV_CHMAP_SL},		/* side left */
32 	{"sr", SNDRV_CHMAP_SR},		/* side right */
33 	{"rc", SNDRV_CHMAP_RC},		/* rear center */
34 	{"flc", SNDRV_CHMAP_FLC},	/* front left center */
35 	{"frc", SNDRV_CHMAP_FRC},	/* front right center */
36 	{"rlc", SNDRV_CHMAP_RLC},	/* rear left center */
37 	{"rrc", SNDRV_CHMAP_RRC},	/* rear right center */
38 	{"flw", SNDRV_CHMAP_FLW},	/* front left wide */
39 	{"frw", SNDRV_CHMAP_FRW},	/* front right wide */
40 	{"flh", SNDRV_CHMAP_FLH},	/* front left high */
41 	{"fch", SNDRV_CHMAP_FCH},	/* front center high */
42 	{"frh", SNDRV_CHMAP_FRH},	/* front right high */
43 	{"tc", SNDRV_CHMAP_TC},		/* top center */
44 	{"tfl", SNDRV_CHMAP_TFL},	/* top front left */
45 	{"tfr", SNDRV_CHMAP_TFR},	/* top front right */
46 	{"tfc", SNDRV_CHMAP_TFC},	/* top front center */
47 	{"trl", SNDRV_CHMAP_TRL},	/* top rear left */
48 	{"trr", SNDRV_CHMAP_TRR},	/* top rear right */
49 	{"trc", SNDRV_CHMAP_TRC},	/* top rear center */
50 	{"tflc", SNDRV_CHMAP_TFLC},	/* top front left center */
51 	{"tfrc", SNDRV_CHMAP_TFRC},	/* top front right center */
52 	{"tsl", SNDRV_CHMAP_TSL},	/* top side left */
53 	{"tsr", SNDRV_CHMAP_TSR},	/* top side right */
54 	{"llfe", SNDRV_CHMAP_LLFE},	/* left LFE */
55 	{"rlfe", SNDRV_CHMAP_RLFE},	/* right LFE */
56 	{"bc", SNDRV_CHMAP_BC},		/* bottom center */
57 	{"blc", SNDRV_CHMAP_BLC},	/* bottom left center */
58 	{"brc", SNDRV_CHMAP_BRC},	/* bottom right center */
59 };
60 
61 
lookup_channel(const char *c)62 static int lookup_channel(const char *c)
63 {
64 	unsigned int i;
65 
66 	for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
67 		if (strcasecmp(channel_map[i].name, c) == 0) {
68 			return channel_map[i].id;
69 		}
70 	}
71 
72 	return -EINVAL;
73 }
74 
tplg_channel_name(int type)75 const char *tplg_channel_name(int type)
76 {
77 	unsigned int i;
78 
79 	for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
80 		if (channel_map[i].id == type)
81 			return channel_map[i].name;
82 	}
83 
84 	return NULL;
85 }
86 
87 /* Parse a channel mapping. */
tplg_parse_channel(snd_tplg_t *tplg, snd_config_t *cfg, void *private)88 int tplg_parse_channel(snd_tplg_t *tplg, snd_config_t *cfg,
89 		       void *private)
90 {
91 	snd_config_iterator_t i, next;
92 	snd_config_t *n;
93 	struct snd_soc_tplg_channel *channel = private;
94 	const char *id;
95 	int channel_id, value;
96 
97 	if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN)
98 		return -EINVAL;
99 
100 	channel += tplg->channel_idx;
101 	snd_config_get_id(cfg, &id);
102 	tplg_dbg("\tChannel %s at index %d", id, tplg->channel_idx);
103 
104 	channel_id = lookup_channel(id);
105 	if (channel_id < 0) {
106 		SNDERR("invalid channel %s", id);
107 		return -EINVAL;
108 	}
109 
110 	channel->id = channel_id;
111 	channel->size = sizeof(*channel);
112 	tplg_dbg("\tChan %s = %d", id, channel->id);
113 
114 	snd_config_for_each(i, next, cfg) {
115 
116 		n = snd_config_iterator_entry(i);
117 
118 		/* get id */
119 		if (snd_config_get_id(n, &id) < 0)
120 			continue;
121 
122 		/* get value */
123 		if (tplg_get_integer(n, &value, 0) < 0)
124 			continue;
125 
126 		if (strcmp(id, "reg") == 0)
127 			channel->reg = value;
128 		else if (strcmp(id, "shift") == 0)
129 			channel->shift = value;
130 
131 		tplg_dbg("\t\t%s = %d", id, value);
132 	}
133 
134 	tplg->channel_idx++;
135 	return 0;
136 }
137 
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)138 int tplg_save_channels(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
139 		       struct snd_soc_tplg_channel *channel,
140 		       unsigned int count, struct tplg_buf *dst,
141 		       const char *pfx)
142 {
143 	struct snd_soc_tplg_channel *c;
144 	const char *s;
145 	unsigned int index;
146 	int err;
147 
148 	if (count == 0)
149 		return 0;
150 	err = tplg_save_printf(dst, pfx, "channel {\n");
151 	for (index = 0; err >= 0 && index < count; index++) {
152 		c = channel + index;
153 		s = tplg_channel_name(c->id);
154 		if (s == NULL)
155 			err = tplg_save_printf(dst, pfx, "\t%u", c->id);
156 		else
157 			err = tplg_save_printf(dst, pfx, "\t%s", s);
158 		if (err >= 0)
159 			err = tplg_save_printf(dst, NULL, " {\n");
160 		if (err >= 0)
161 			err = tplg_save_printf(dst, pfx, "\t\treg %d\n", c->reg);
162 		if (err >= 0 && c->shift > 0)
163 			err = tplg_save_printf(dst, pfx, "\t\tshift %u\n", c->shift);
164 		if (err >= 0)
165 			err = tplg_save_printf(dst, pfx, "\t}\n");
166 	}
167 	if (err >= 0)
168 		err = tplg_save_printf(dst, pfx, "}\n");
169 	return err;
170 }
171