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 "list.h"
21 #include "tplg_local.h"
22
23 /* mapping of channel text names to types */
24 static const struct map_elem channel_map[] = {
25 {"mono", SNDRV_CHMAP_MONO}, /* mono stream */
26 {"fl", SNDRV_CHMAP_FL}, /* front left */
27 {"fr", SNDRV_CHMAP_FR}, /* front right */
28 {"rl", SNDRV_CHMAP_RL}, /* rear left */
29 {"rr", SNDRV_CHMAP_RR}, /* rear right */
30 {"fc", SNDRV_CHMAP_FC}, /* front center */
31 {"lfe", SNDRV_CHMAP_LFE}, /* LFE */
32 {"sl", SNDRV_CHMAP_SL}, /* side left */
33 {"sr", SNDRV_CHMAP_SR}, /* side right */
34 {"rc", SNDRV_CHMAP_RC}, /* rear center */
35 {"flc", SNDRV_CHMAP_FLC}, /* front left center */
36 {"frc", SNDRV_CHMAP_FRC}, /* front right center */
37 {"rlc", SNDRV_CHMAP_RLC}, /* rear left center */
38 {"rrc", SNDRV_CHMAP_RRC}, /* rear right center */
39 {"flw", SNDRV_CHMAP_FLW}, /* front left wide */
40 {"frw", SNDRV_CHMAP_FRW}, /* front right wide */
41 {"flh", SNDRV_CHMAP_FLH}, /* front left high */
42 {"fch", SNDRV_CHMAP_FCH}, /* front center high */
43 {"frh", SNDRV_CHMAP_FRH}, /* front right high */
44 {"tc", SNDRV_CHMAP_TC}, /* top center */
45 {"tfl", SNDRV_CHMAP_TFL}, /* top front left */
46 {"tfr", SNDRV_CHMAP_TFR}, /* top front right */
47 {"tfc", SNDRV_CHMAP_TFC}, /* top front center */
48 {"trl", SNDRV_CHMAP_TRL}, /* top rear left */
49 {"trr", SNDRV_CHMAP_TRR}, /* top rear right */
50 {"trc", SNDRV_CHMAP_TRC}, /* top rear center */
51 {"tflc", SNDRV_CHMAP_TFLC}, /* top front left center */
52 {"tfrc", SNDRV_CHMAP_TFRC}, /* top front right center */
53 {"tsl", SNDRV_CHMAP_TSL}, /* top side left */
54 {"tsr", SNDRV_CHMAP_TSR}, /* top side right */
55 {"llfe", SNDRV_CHMAP_LLFE}, /* left LFE */
56 {"rlfe", SNDRV_CHMAP_RLFE}, /* right LFE */
57 {"bc", SNDRV_CHMAP_BC}, /* bottom center */
58 {"blc", SNDRV_CHMAP_BLC}, /* bottom left center */
59 {"brc", SNDRV_CHMAP_BRC}, /* bottom right center */
60 };
61
62
lookup_channel(const char * c)63 static int lookup_channel(const char *c)
64 {
65 unsigned int i;
66
67 for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
68 if (strcasecmp(channel_map[i].name, c) == 0) {
69 return channel_map[i].id;
70 }
71 }
72
73 return -EINVAL;
74 }
75
tplg_channel_name(int type)76 const char *tplg_channel_name(int type)
77 {
78 unsigned int i;
79
80 for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
81 if (channel_map[i].id == type)
82 return channel_map[i].name;
83 }
84
85 return NULL;
86 }
87
88 /* Parse a channel mapping. */
tplg_parse_channel(snd_tplg_t * tplg,snd_config_t * cfg,void * private)89 int tplg_parse_channel(snd_tplg_t *tplg, snd_config_t *cfg,
90 void *private)
91 {
92 snd_config_iterator_t i, next;
93 snd_config_t *n;
94 struct snd_soc_tplg_channel *channel = private;
95 const char *id;
96 int channel_id, value;
97
98 if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN)
99 return -EINVAL;
100
101 channel += tplg->channel_idx;
102 snd_config_get_id(cfg, &id);
103 tplg_dbg("\tChannel %s at index %d", id, tplg->channel_idx);
104
105 channel_id = lookup_channel(id);
106 if (channel_id < 0) {
107 SNDERR("invalid channel %s", id);
108 return -EINVAL;
109 }
110
111 channel->id = channel_id;
112 channel->size = sizeof(*channel);
113 tplg_dbg("\tChan %s = %d", id, channel->id);
114
115 snd_config_for_each(i, next, cfg) {
116
117 n = snd_config_iterator_entry(i);
118
119 /* get id */
120 if (snd_config_get_id(n, &id) < 0)
121 continue;
122
123 /* get value */
124 if (tplg_get_integer(n, &value, 0) < 0)
125 continue;
126
127 if (strcmp(id, "reg") == 0)
128 channel->reg = value;
129 else if (strcmp(id, "shift") == 0)
130 channel->shift = value;
131
132 tplg_dbg("\t\t%s = %d", id, value);
133 }
134
135 tplg->channel_idx++;
136 return 0;
137 }
138
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)139 int tplg_save_channels(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
140 struct snd_soc_tplg_channel *channel,
141 unsigned int count, struct tplg_buf *dst,
142 const char *pfx)
143 {
144 struct snd_soc_tplg_channel *c;
145 const char *s;
146 unsigned int index;
147 int err;
148
149 if (count == 0)
150 return 0;
151 err = tplg_save_printf(dst, pfx, "channel {\n");
152 for (index = 0; err >= 0 && index < count; index++) {
153 c = channel + index;
154 s = tplg_channel_name(c->id);
155 if (s == NULL)
156 err = tplg_save_printf(dst, pfx, "\t%u", c->id);
157 else
158 err = tplg_save_printf(dst, pfx, "\t%s", s);
159 if (err >= 0)
160 err = tplg_save_printf(dst, NULL, " {\n");
161 if (err >= 0)
162 err = tplg_save_printf(dst, pfx, "\t\treg %d\n", c->reg);
163 if (err >= 0 && c->shift > 0)
164 err = tplg_save_printf(dst, pfx, "\t\tshift %u\n", c->shift);
165 if (err >= 0)
166 err = tplg_save_printf(dst, pfx, "\t}\n");
167 }
168 if (err >= 0)
169 err = tplg_save_printf(dst, pfx, "}\n");
170 return err;
171 }
172