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