OSDN Git Service

1d31b4944abf8bcd9f326e89f817447a502c32cc
[android-x86/external-alsa-lib.git] / src / topology / ctl.c
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 #define ENUM_VAL_SIZE   (SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2)
24
25 struct ctl_access_elem {
26         const char *name;
27         unsigned int value;
28 };
29
30 /* CTL access strings and codes */
31 /* place the multi-bit values on top - like read_write - for save */
32 static const struct ctl_access_elem ctl_access[] = {
33         {"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE},
34         {"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE},
35         {"read", SNDRV_CTL_ELEM_ACCESS_READ},
36         {"write", SNDRV_CTL_ELEM_ACCESS_WRITE},
37         {"volatile", SNDRV_CTL_ELEM_ACCESS_VOLATILE},
38         {"tlv_read", SNDRV_CTL_ELEM_ACCESS_TLV_READ},
39         {"tlv_write", SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
40         {"tlv_command", SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
41         {"inactive", SNDRV_CTL_ELEM_ACCESS_INACTIVE},
42         {"lock", SNDRV_CTL_ELEM_ACCESS_LOCK},
43         {"owner", SNDRV_CTL_ELEM_ACCESS_OWNER},
44         {"tlv_callback", SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK},
45 };
46
47 /* find CTL access strings and conver to values */
48 static int parse_access_values(snd_config_t *cfg,
49                                struct snd_soc_tplg_ctl_hdr *hdr)
50 {
51         snd_config_iterator_t i, next;
52         snd_config_t *n;
53         const char *value = NULL;
54         unsigned int j;
55
56         tplg_dbg(" Access:");
57
58         snd_config_for_each(i, next, cfg) {
59                 n = snd_config_iterator_entry(i);
60
61                 /* get value */
62                 if (snd_config_get_string(n, &value) < 0)
63                         continue;
64
65                 /* match access value and set flags */
66                 for (j = 0; j < ARRAY_SIZE(ctl_access); j++) {
67                         if (strcmp(value, ctl_access[j].name) == 0) {
68                                 hdr->access |= ctl_access[j].value;
69                                 tplg_dbg("\t%s", value);
70                                 break;
71                         }
72                 }
73         }
74
75         return 0;
76 }
77
78 /* Parse Access */
79 int parse_access(snd_config_t *cfg,
80                  struct snd_soc_tplg_ctl_hdr *hdr)
81 {
82         snd_config_iterator_t i, next;
83         snd_config_t *n;
84         const char *id;
85         int err = 0;
86
87         snd_config_for_each(i, next, cfg) {
88
89                 n = snd_config_iterator_entry(i);
90                 if (snd_config_get_id(n, &id) < 0)
91                         continue;
92
93                 if (strcmp(id, "access") == 0) {
94                         err = parse_access_values(n, hdr);
95                         if (err < 0) {
96                                 SNDERR("failed to parse access");
97                                 return err;
98                         }
99                         continue;
100                 }
101         }
102
103         return err;
104 }
105
106 /* Save Access */
107 static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
108                             struct snd_soc_tplg_ctl_hdr *hdr, char **dst,
109                             const char *pfx)
110 {
111         const char *last;
112         unsigned int j, count, access, cval;
113         int err;
114
115         if (hdr->access == 0)
116                 return 0;
117
118         access = hdr->access;
119         for (j = 0, count = 0, last = NULL; j < ARRAY_SIZE(ctl_access); j++) {
120                 cval = ctl_access[j].value;
121                 if ((access & cval) == cval) {
122                         access &= ~cval;
123                         last = ctl_access[j].name;
124                         count++;
125                 }
126         }
127         if (count == 1)
128                 return tplg_save_printf(dst, pfx, "access.0 %s\n", last);
129         err = tplg_save_printf(dst, pfx, "access [\n");
130         if (err < 0)
131                 return err;
132         access = hdr->access;
133         for (j = 0; j < ARRAY_SIZE(ctl_access); j++) {
134                 cval = ctl_access[j].value;
135                 if ((access & cval) == cval) {
136                         err = tplg_save_printf(dst, pfx, "\t%s\n",
137                                                ctl_access[j].name);
138                         if (err < 0)
139                                 return err;
140                         access &= ~cval;
141                 }
142         }
143         return tplg_save_printf(dst, pfx, "]\n");
144 }
145
146 /* copy referenced TLV to the mixer control */
147 static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
148 {
149         struct snd_soc_tplg_mixer_control *mixer_ctrl =  elem->mixer_ctrl;
150         struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
151
152         tplg_dbg("TLV '%s' used by '%s", ref->id, elem->id);
153
154         /* TLV has a fixed size */
155         mixer_ctrl->hdr.tlv = *tlv;
156         return 0;
157 }
158
159 /* check referenced TLV for a mixer control */
160 static int tplg_build_mixer_control(snd_tplg_t *tplg,
161                                     struct tplg_elem *elem)
162 {
163         struct tplg_ref *ref;
164         struct list_head *base, *pos;
165         int err = 0;
166
167         base = &elem->ref_list;
168
169         /* for each ref in this control elem */
170         list_for_each(pos, base) {
171
172                 ref = list_entry(pos, struct tplg_ref, list);
173                 if (ref->elem)
174                         continue;
175
176                 if (ref->type == SND_TPLG_TYPE_TLV) {
177                         ref->elem = tplg_elem_lookup(&tplg->tlv_list,
178                                 ref->id, SND_TPLG_TYPE_TLV, elem->index);
179                         if (ref->elem)
180                                  err = copy_tlv(elem, ref->elem);
181
182                 } else if (ref->type == SND_TPLG_TYPE_DATA) {
183                         err = tplg_copy_data(tplg, elem, ref);
184                         if (err < 0)
185                                 return err;
186                 }
187
188                 if (!ref->elem) {
189                         SNDERR("cannot find '%s' referenced by"
190                                 " control '%s'", ref->id, elem->id);
191                         return -EINVAL;
192                 } else if (err < 0)
193                         return err;
194         }
195
196         return 0;
197 }
198
199 static void copy_enum_texts(struct tplg_elem *enum_elem,
200                             struct tplg_elem *ref_elem)
201 {
202         struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
203         struct tplg_texts *texts = ref_elem->texts;
204
205         memcpy(ec->texts, texts->items,
206                 SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
207         ec->items += texts->num_items;
208 }
209
210 /* check referenced text for a enum control */
211 static int tplg_build_enum_control(snd_tplg_t *tplg,
212                                    struct tplg_elem *elem)
213 {
214         struct tplg_ref *ref;
215         struct list_head *base, *pos;
216         int err;
217
218         base = &elem->ref_list;
219
220         list_for_each(pos, base) {
221
222                 ref = list_entry(pos, struct tplg_ref, list);
223                 if (ref->elem)
224                         continue;
225
226                 if (ref->type == SND_TPLG_TYPE_TEXT) {
227                         ref->elem = tplg_elem_lookup(&tplg->text_list,
228                                 ref->id, SND_TPLG_TYPE_TEXT, elem->index);
229                         if (ref->elem)
230                                 copy_enum_texts(elem, ref->elem);
231
232                 } else if (ref->type == SND_TPLG_TYPE_DATA) {
233                         err = tplg_copy_data(tplg, elem, ref);
234                         if (err < 0)
235                                 return err;
236                 }
237                 if (!ref->elem) {
238                         SNDERR("cannot find '%s' referenced by"
239                                 " control '%s'", ref->id, elem->id);
240                         return -EINVAL;
241                 }
242         }
243
244         return 0;
245 }
246
247 /* check referenced private data for a byte control */
248 static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
249 {
250         struct tplg_ref *ref;
251         struct list_head *base, *pos;
252         int err;
253
254         base = &elem->ref_list;
255
256         list_for_each(pos, base) {
257
258                 ref = list_entry(pos, struct tplg_ref, list);
259                 if (ref->elem)
260                         continue;
261
262                  if (ref->type == SND_TPLG_TYPE_DATA) {
263                         err = tplg_copy_data(tplg, elem, ref);
264                         if (err < 0)
265                                 return err;
266                 }
267         }
268
269         return 0;
270 }
271
272 int tplg_build_controls(snd_tplg_t *tplg)
273 {
274         struct list_head *base, *pos;
275         struct tplg_elem *elem;
276         int err = 0;
277
278         base = &tplg->mixer_list;
279         list_for_each(pos, base) {
280
281                 elem = list_entry(pos, struct tplg_elem, list);
282                 err = tplg_build_mixer_control(tplg, elem);
283                 if (err < 0)
284                         return err;
285
286                 /* add control to manifest */
287                 tplg->manifest.control_elems++;
288         }
289
290         base = &tplg->enum_list;
291         list_for_each(pos, base) {
292
293                 elem = list_entry(pos, struct tplg_elem, list);
294                 err = tplg_build_enum_control(tplg, elem);
295                 if (err < 0)
296                         return err;
297
298                 /* add control to manifest */
299                 tplg->manifest.control_elems++;
300         }
301
302         base = &tplg->bytes_ext_list;
303         list_for_each(pos, base) {
304
305                 elem = list_entry(pos, struct tplg_elem, list);
306                 err = tplg_build_bytes_control(tplg, elem);
307                 if (err < 0)
308                         return err;
309
310                 /* add control to manifest */
311                 tplg->manifest.control_elems++;
312         }
313
314         return 0;
315 }
316
317
318 /*
319  * Parse TLV of DBScale type.
320  *
321  * Parse DBScale describing min, step, mute in DB.
322  */
323 static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem)
324 {
325         snd_config_iterator_t i, next;
326         snd_config_t *n;
327         struct snd_soc_tplg_ctl_tlv *tplg_tlv = elem->tlv;
328         struct snd_soc_tplg_tlv_dbscale *scale;
329         const char *id = NULL;
330         int val;
331
332         tplg_dbg(" scale: %s", elem->id);
333
334         tplg_tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
335         tplg_tlv->type = SNDRV_CTL_TLVT_DB_SCALE;
336         scale = &tplg_tlv->scale;
337
338         snd_config_for_each(i, next, cfg) {
339
340                 n = snd_config_iterator_entry(i);
341
342                 /* get ID */
343                 if (snd_config_get_id(n, &id) < 0)
344                         return -EINVAL;
345
346                 /* get value */
347                 if (tplg_get_integer(n, &val, 0))
348                         continue;
349
350                 tplg_dbg("\t%s = %i", id, val);
351
352                 /* get TLV data */
353                 if (strcmp(id, "min") == 0)
354                         scale->min = val;
355                 else if (strcmp(id, "step") == 0)
356                         scale->step = val;
357                 else if (strcmp(id, "mute") == 0)
358                         scale->mute = val;
359                 else
360                         SNDERR("unknown id '%s'", id);
361         }
362
363         return 0;
364 }
365
366 /* Parse TLV */
367 int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
368                    void *private ATTRIBUTE_UNUSED)
369 {
370         snd_config_iterator_t i, next;
371         snd_config_t *n;
372         const char *id;
373         int err = 0;
374         struct tplg_elem *elem;
375
376         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV);
377         if (!elem)
378                 return -ENOMEM;
379
380         snd_config_for_each(i, next, cfg) {
381
382                 n = snd_config_iterator_entry(i);
383                 if (snd_config_get_id(n, &id) < 0)
384                         continue;
385
386                 if (strcmp(id, "scale") == 0) {
387                         err = tplg_parse_tlv_dbscale(n, elem);
388                         if (err < 0) {
389                                 SNDERR("failed to DBScale");
390                                 return err;
391                         }
392                         continue;
393                 }
394         }
395
396         return err;
397 }
398
399 /* save TLV data */
400 int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
401                   struct tplg_elem *elem,
402                   char **dst, const char *pfx)
403 {
404         struct snd_soc_tplg_ctl_tlv *tlv = elem->tlv;
405         struct snd_soc_tplg_tlv_dbscale *scale;
406         int err;
407
408         if (tlv->type != SNDRV_CTL_TLVT_DB_SCALE) {
409                 SNDERR("unknown TLV type");
410                 return -EINVAL;
411         }
412
413         scale = &tlv->scale;
414         err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
415         if (err >= 0)
416                 err = tplg_save_printf(dst, pfx, "\tscale {\n");
417         if (err >= 0 && scale->min)
418                 err = tplg_save_printf(dst, pfx, "\t\tmin %i\n", scale->min);
419         if (err >= 0 && scale->step > 0)
420                 err = tplg_save_printf(dst, pfx, "\t\tstep %i\n", scale->step);
421         if (err >= 0 && scale->mute > 0)
422                 err = tplg_save_printf(dst, pfx, "\t\tmute %i\n", scale->mute);
423         if (err >= 0)
424                 err = tplg_save_printf(dst, pfx, "\t}\n");
425         if (err >= 0)
426                 err = tplg_save_printf(dst, pfx, "}\n");
427         return err;
428 }
429
430 /* Parse Control Bytes */
431 int tplg_parse_control_bytes(snd_tplg_t *tplg,
432                              snd_config_t *cfg,
433                              void *private ATTRIBUTE_UNUSED)
434 {
435         struct snd_soc_tplg_bytes_control *be;
436         struct tplg_elem *elem;
437         snd_config_iterator_t i, next;
438         snd_config_t *n;
439         const char *id, *val = NULL;
440         int err, ival;
441         bool access_set = false, tlv_set = false;
442
443         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES);
444         if (!elem)
445                 return -ENOMEM;
446
447         be = elem->bytes_ext;
448         be->size = elem->size;
449         snd_strlcpy(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
450         be->hdr.type = SND_SOC_TPLG_TYPE_BYTES;
451
452         tplg_dbg(" Control Bytes: %s", elem->id);
453
454         snd_config_for_each(i, next, cfg) {
455                 n = snd_config_iterator_entry(i);
456                 if (snd_config_get_id(n, &id) < 0)
457                         continue;
458
459                 /* skip comments */
460                 if (strcmp(id, "comment") == 0)
461                         continue;
462                 if (id[0] == '#')
463                         continue;
464
465                 if (strcmp(id, "base") == 0) {
466                         if (tplg_get_integer(n, &ival, 0))
467                                 return -EINVAL;
468
469                         be->base = ival;
470                         tplg_dbg("\t%s: %d", id, be->base);
471                         continue;
472                 }
473
474                 if (strcmp(id, "num_regs") == 0) {
475                         if (tplg_get_integer(n, &ival, 0))
476                                 return -EINVAL;
477
478                         be->num_regs = ival;
479                         tplg_dbg("\t%s: %d", id, be->num_regs);
480                         continue;
481                 }
482
483                 if (strcmp(id, "max") == 0) {
484                         if (tplg_get_integer(n, &ival, 0))
485                                 return -EINVAL;
486
487                         be->max = ival;
488                         tplg_dbg("\t%s: %d", id, be->max);
489                         continue;
490                 }
491
492                 if (strcmp(id, "mask") == 0) {
493                         if (tplg_get_integer(n, &ival, 16))
494                                 return -EINVAL;
495
496                         be->mask = ival;
497                         tplg_dbg("\t%s: %d", id, be->mask);
498                         continue;
499                 }
500
501                 if (strcmp(id, "data") == 0) {
502                         err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
503                         if (err < 0)
504                                 return err;
505                         continue;
506                 }
507
508                 if (strcmp(id, "tlv") == 0) {
509                         if (snd_config_get_string(n, &val) < 0)
510                                 return -EINVAL;
511
512                         err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
513                         if (err < 0)
514                                 return err;
515
516                         tlv_set = true;
517                         tplg_dbg("\t%s: %s", id, val);
518                         continue;
519                 }
520
521                 if (strcmp(id, "ops") == 0) {
522                         err = tplg_parse_compound(tplg, n, tplg_parse_ops,
523                                 &be->hdr);
524                         if (err < 0)
525                                 return err;
526                         continue;
527                 }
528
529                 if (strcmp(id, "extops") == 0) {
530                         err = tplg_parse_compound(tplg, n, tplg_parse_ext_ops,
531                                 be);
532                         if (err < 0)
533                                 return err;
534                         continue;
535                 }
536
537                 if (strcmp(id, "access") == 0) {
538                         err = parse_access(cfg, &be->hdr);
539                         if (err < 0)
540                                 return err;
541                         access_set = true;
542                         continue;
543                 }
544         }
545
546         /* set CTL access to default values if none are provided */
547         if (!access_set) {
548
549                 be->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
550                 if (tlv_set)
551                         be->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
552         }
553
554         return 0;
555 }
556
557 /* save control bytes */
558 int tplg_save_control_bytes(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
559                             struct tplg_elem *elem,
560                             char **dst, const char *pfx)
561 {
562         struct snd_soc_tplg_bytes_control *be = elem->bytes_ext;
563         char pfx2[16];
564         int err;
565
566         if (!be)
567                 return 0;
568
569         snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
570         err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
571         if (err < 0)
572                 return err;
573         if (err >= 0 && elem->index > 0)
574                 err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
575         if (err >= 0 && be->base > 0)
576                 err = tplg_save_printf(dst, pfx, "\tbase %u\n", be->base);
577         if (err >= 0 && be->num_regs > 0)
578                 err = tplg_save_printf(dst, pfx, "\tnum_regs %u\n", be->num_regs);
579         if (err >= 0 && be->max > 0)
580                 err = tplg_save_printf(dst, pfx, "\tmax %u\n", be->max);
581         if (err >= 0 && be->mask > 0)
582                 err = tplg_save_printf(dst, pfx, "\tmask %u\n", be->mask);
583         if (err >= 0)
584                 err = tplg_save_ops(tplg, &be->hdr, dst, pfx2);
585         if (err >= 0)
586                 err = tplg_save_ext_ops(tplg, be, dst, pfx2);
587         if (err >= 0)
588                 err = tplg_save_access(tplg, &be->hdr, dst, pfx2);
589         if (err >= 0)
590                 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
591                                      "tlv", dst, pfx2);
592         if (err >= 0)
593                 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
594                                      "data", dst, pfx2);
595         if (err >= 0)
596                 err = tplg_save_printf(dst, pfx, "}\n");
597         return err;
598 }
599
600 /* Parse Control Enums. */
601 int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
602                             void *private ATTRIBUTE_UNUSED)
603 {
604         struct snd_soc_tplg_enum_control *ec;
605         struct tplg_elem *elem;
606         snd_config_iterator_t i, next;
607         snd_config_t *n;
608         const char *id, *val = NULL;
609         int err, j;
610         bool access_set = false;
611
612         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM);
613         if (!elem)
614                 return -ENOMEM;
615
616         ec = elem->enum_ctrl;
617         snd_strlcpy(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
618         ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM;
619         ec->size = elem->size;
620         tplg->channel_idx = 0;
621
622         /* set channel reg to default state */
623         for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++) {
624                 ec->channel[j].reg = -1;
625         }
626
627         tplg_dbg(" Control Enum: %s", elem->id);
628
629         snd_config_for_each(i, next, cfg) {
630
631                 n = snd_config_iterator_entry(i);
632                 if (snd_config_get_id(n, &id) < 0)
633                         continue;
634
635                 /* skip comments */
636                 if (strcmp(id, "comment") == 0)
637                         continue;
638                 if (id[0] == '#')
639                         continue;
640
641                 if (strcmp(id, "texts") == 0) {
642                         if (snd_config_get_string(n, &val) < 0)
643                                 return -EINVAL;
644
645                         tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val);
646                         tplg_dbg("\t%s: %s", id, val);
647                         continue;
648                 }
649
650                 if (strcmp(id, "channel") == 0) {
651                         if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
652                                 SNDERR("too many channels %s", elem->id);
653                                 return -EINVAL;
654                         }
655
656                         err = tplg_parse_compound(tplg, n, tplg_parse_channel,
657                                 ec->channel);
658                         if (err < 0)
659                                 return err;
660
661                         ec->num_channels = tplg->channel_idx;
662                         continue;
663                 }
664
665                 if (strcmp(id, "ops") == 0) {
666                         err = tplg_parse_compound(tplg, n, tplg_parse_ops,
667                                 &ec->hdr);
668                         if (err < 0)
669                                 return err;
670                         continue;
671                 }
672
673                 if (strcmp(id, "data") == 0) {
674                         err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
675                         if (err < 0)
676                                 return err;
677                         continue;
678                 }
679
680                 if (strcmp(id, "access") == 0) {
681                         err = parse_access(cfg, &ec->hdr);
682                         if (err < 0)
683                                 return err;
684                         access_set = true;
685                         continue;
686                 }
687         }
688
689         /* set CTL access to default values if none are provided */
690         if (!access_set) {
691                 ec->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
692         }
693
694         return 0;
695 }
696
697 /* save control eunm */
698 int tplg_save_control_enum(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
699                            struct tplg_elem *elem,
700                            char **dst, const char *pfx)
701 {
702         struct snd_soc_tplg_enum_control *ec = elem->enum_ctrl;
703         char pfx2[16];
704         int err;
705
706         if (!ec)
707                 return 0;
708
709         snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
710         err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
711         if (err < 0)
712                 return err;
713         if (err >= 0 && elem->index > 0)
714                 err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
715         if (err >= 0)
716                 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TEXT,
717                                      "texts", dst, pfx2);
718         if (err >= 0)
719                 err = tplg_save_channels(tplg, ec->channel, ec->num_channels,
720                                          dst, pfx2);
721         if (err >= 0)
722                 err = tplg_save_ops(tplg, &ec->hdr, dst, pfx2);
723         if (err >= 0)
724                 err = tplg_save_access(tplg, &ec->hdr, dst, pfx2);
725         if (err >= 0)
726                 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
727                                      "data", dst, pfx2);
728         if (err >= 0)
729                 err = tplg_save_printf(dst, pfx, "}\n");
730         return err;
731 }
732
733 /* Parse Controls.
734  *
735  * Mixer control. Supports multiple channels.
736  */
737 int tplg_parse_control_mixer(snd_tplg_t *tplg,
738                              snd_config_t *cfg,
739                              void *private ATTRIBUTE_UNUSED)
740 {
741         struct snd_soc_tplg_mixer_control *mc;
742         struct tplg_elem *elem;
743         snd_config_iterator_t i, next;
744         snd_config_t *n;
745         const char *id, *val = NULL;
746         int err, j, ival;
747         bool access_set = false, tlv_set = false;
748
749         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MIXER);
750         if (!elem)
751                 return -ENOMEM;
752
753         /* init new mixer */
754         mc = elem->mixer_ctrl;
755         snd_strlcpy(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
756         mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER;
757         mc->size = elem->size;
758         tplg->channel_idx = 0;
759
760         /* set channel reg to default state */
761         for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
762                 mc->channel[j].reg = -1;
763
764         tplg_dbg(" Control Mixer: %s", elem->id);
765
766         /* giterate trough each mixer elment */
767         snd_config_for_each(i, next, cfg) {
768                 n = snd_config_iterator_entry(i);
769                 if (snd_config_get_id(n, &id) < 0)
770                         continue;
771
772                 /* skip comments */
773                 if (strcmp(id, "comment") == 0)
774                         continue;
775                 if (id[0] == '#')
776                         continue;
777
778                 if (strcmp(id, "channel") == 0) {
779                         if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
780                                 SNDERR("too many channels %s", elem->id);
781                                 return -EINVAL;
782                         }
783
784                         err = tplg_parse_compound(tplg, n, tplg_parse_channel,
785                                 mc->channel);
786                         if (err < 0)
787                                 return err;
788
789                         mc->num_channels = tplg->channel_idx;
790                         continue;
791                 }
792
793                 if (strcmp(id, "max") == 0) {
794                         if (tplg_get_integer(n, &ival, 0))
795                                 return -EINVAL;
796
797                         mc->max = ival;
798                         tplg_dbg("\t%s: %d", id, mc->max);
799                         continue;
800                 }
801
802                 if (strcmp(id, "invert") == 0) {
803                         ival = snd_config_get_bool(n);
804                         if (ival < 0)
805                                 return -EINVAL;
806                         mc->invert = ival;
807
808                         tplg_dbg("\t%s: %d", id, mc->invert);
809                         continue;
810                 }
811
812                 if (strcmp(id, "ops") == 0) {
813                         err = tplg_parse_compound(tplg, n, tplg_parse_ops,
814                                 &mc->hdr);
815                         if (err < 0)
816                                 return err;
817                         continue;
818                 }
819
820                 if (strcmp(id, "tlv") == 0) {
821                         if (snd_config_get_string(n, &val) < 0)
822                                 return -EINVAL;
823
824                         err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
825                         if (err < 0)
826                                 return err;
827
828                         tlv_set = true;
829                         tplg_dbg("\t%s: %s", id, val);
830                         continue;
831                 }
832
833                 if (strcmp(id, "data") == 0) {
834                         err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
835                         if (err < 0)
836                                 return err;
837                         continue;
838                 }
839
840                 if (strcmp(id, "access") == 0) {
841                         err = parse_access(cfg, &mc->hdr);
842                         if (err < 0)
843                                 return err;
844                         access_set = true;
845                         continue;
846                 }
847         }
848
849         /* set CTL access to default values if none are provided */
850         if (!access_set) {
851
852                 mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
853                 if (tlv_set)
854                         mc->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
855         }
856
857         return 0;
858 }
859
860 int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
861                             struct tplg_elem *elem, char **dst,
862                             const char *pfx)
863 {
864         struct snd_soc_tplg_mixer_control *mc = elem->mixer_ctrl;
865         char pfx2[16];
866         int err;
867
868         if (!mc)
869                 return 0;
870         err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
871         if (err < 0)
872                 return err;
873         snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
874         if (err >= 0 && elem->index > 0)
875                 err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
876         if (err >= 0)
877                 err = tplg_save_channels(tplg, mc->channel, mc->num_channels,
878                                          dst, pfx2);
879         if (err >= 0 && mc->max > 0)
880                 err = tplg_save_printf(dst, pfx, "\tmax %u\n", mc->max);
881         if (err >= 0 && mc->invert > 0)
882                 err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max);
883         if (err >= 0 && mc->invert > 0)
884                 err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max);
885         if (err >= 0)
886                 err = tplg_save_ops(tplg, &mc->hdr, dst, pfx2);
887         if (err >= 0)
888                 err = tplg_save_access(tplg, &mc->hdr, dst, pfx2);
889         if (err >= 0)
890                 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
891                                      "tlv", dst, pfx2);
892         if (err >= 0)
893                 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
894                                      "data", dst, pfx2);
895         if (err >= 0)
896                 err = tplg_save_printf(dst, pfx, "}\n");
897         return err;
898 }
899
900 static int init_ctl_hdr(snd_tplg_t *tplg,
901                         struct tplg_elem *parent,
902                         struct snd_soc_tplg_ctl_hdr *hdr,
903                         struct snd_tplg_ctl_template *t)
904 {
905         struct tplg_elem *elem;
906         int err;
907
908         hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr);
909         hdr->type = t->type;
910
911         snd_strlcpy(hdr->name, t->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
912
913         /* clean up access flag */
914         if (t->access == 0)
915                 t->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
916         t->access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
917                 SNDRV_CTL_ELEM_ACCESS_VOLATILE |
918                 SNDRV_CTL_ELEM_ACCESS_INACTIVE |
919                 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
920                 SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
921                 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
922
923         hdr->access = t->access;
924         hdr->ops.get = t->ops.get;
925         hdr->ops.put = t->ops.put;
926         hdr->ops.info = t->ops.info;
927
928         /* TLV */
929         if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
930                 && !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
931
932                 struct snd_tplg_tlv_template *tlvt = t->tlv;
933                 struct snd_soc_tplg_ctl_tlv *tlv;
934                 struct snd_tplg_tlv_dbscale_template *scalet;
935                 struct snd_soc_tplg_tlv_dbscale *scale;
936
937                 if (!tlvt) {
938                         SNDERR("missing TLV data");
939                         return -EINVAL;
940                 }
941
942                 elem = tplg_elem_new_common(tplg, NULL, parent->id,
943                                             SND_TPLG_TYPE_TLV);
944                 if (!elem)
945                         return -ENOMEM;
946
947                 tlv = elem->tlv;
948
949                 err = tplg_ref_add(parent, SND_TPLG_TYPE_TLV, parent->id);
950                 if (err < 0)
951                         return err;
952
953                 tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
954                 tlv->type = tlvt->type;
955
956                 switch (tlvt->type) {
957                 case SNDRV_CTL_TLVT_DB_SCALE:
958                         scalet = container_of(tlvt,
959                                 struct snd_tplg_tlv_dbscale_template, hdr);
960                         scale = &tlv->scale;
961                         scale->min = scalet->min;
962                         scale->step = scalet->step;
963                         scale->mute = scalet->mute;
964                         break;
965
966                 /* TODO: add support for other TLV types */
967                 default:
968                         SNDERR("unsupported TLV type %d", tlv->type);
969                         break;
970                 }
971         }
972
973         return 0;
974 }
975
976 int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
977                    struct tplg_elem **e)
978 {
979         struct snd_soc_tplg_mixer_control *mc;
980         struct snd_soc_tplg_private *priv;
981         struct tplg_elem *elem;
982         int ret, i, num_channels;
983
984         tplg_dbg(" Control Mixer: %s", mixer->hdr.name);
985
986         if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) {
987                 SNDERR("invalid mixer type %d", mixer->hdr.type);
988                 return -EINVAL;
989         }
990
991         elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name,
992                 SND_TPLG_TYPE_MIXER);
993         if (!elem)
994                 return -ENOMEM;
995
996         /* init new mixer */
997         mc = elem->mixer_ctrl;
998         mc->size = elem->size;
999         ret = init_ctl_hdr(tplg, elem, &mc->hdr, &mixer->hdr);
1000         if (ret < 0) {
1001                 tplg_elem_free(elem);
1002                 return ret;
1003         }
1004
1005         mc->min = mixer->min;
1006         mc->max = mixer->max;
1007         mc->platform_max = mixer->platform_max;
1008         mc->invert = mixer->invert;
1009
1010         /* set channel reg to default state */
1011         for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
1012                 mc->channel[i].reg = -1;
1013
1014         num_channels = mixer->map ? mixer->map->num_channels : 0;
1015         mc->num_channels = num_channels;
1016
1017         for (i = 0; i < num_channels; i++) {
1018                 struct snd_tplg_channel_elem *channel = &mixer->map->channel[i];
1019
1020                 mc->channel[i].size = sizeof(mc->channel[0]);
1021                 mc->channel[i].reg = channel->reg;
1022                 mc->channel[i].shift = channel->shift;
1023                 mc->channel[i].id = channel->id;
1024         }
1025
1026         /* priv data */
1027         priv = mixer->priv;
1028         if (priv && priv->size > 0) {
1029                 ret = tplg_add_data(tplg, elem, priv,
1030                                     sizeof(*priv) + priv->size);
1031                 if (ret < 0)
1032                         return ret;
1033         }
1034
1035         if (e)
1036                 *e = elem;
1037         return 0;
1038 }
1039
1040 int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
1041                   struct tplg_elem **e)
1042 {
1043         struct snd_soc_tplg_enum_control *ec;
1044         struct snd_soc_tplg_private *priv;
1045         struct tplg_elem *elem;
1046         int ret, i, num_items, num_channels;
1047
1048         tplg_dbg(" Control Enum: %s", enum_ctl->hdr.name);
1049
1050         if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) {
1051                 SNDERR("invalid enum type %d", enum_ctl->hdr.type);
1052                 return -EINVAL;
1053         }
1054
1055         elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name,
1056                 SND_TPLG_TYPE_ENUM);
1057         if (!elem)
1058                 return -ENOMEM;
1059
1060         ec = elem->enum_ctrl;
1061         ec->size = elem->size;
1062         ret = init_ctl_hdr(tplg, elem, &ec->hdr, &enum_ctl->hdr);
1063         if (ret < 0) {
1064                 tplg_elem_free(elem);
1065                 return ret;
1066         }
1067
1068         num_items =  enum_ctl->items < SND_SOC_TPLG_NUM_TEXTS ?
1069                 enum_ctl->items : SND_SOC_TPLG_NUM_TEXTS;
1070         ec->items = num_items;
1071         ec->mask = enum_ctl->mask;
1072         ec->count = enum_ctl->items;
1073
1074         /* set channel reg to default state */
1075         for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
1076                 ec->channel[i].reg = -1;
1077
1078         num_channels = enum_ctl->map ? enum_ctl->map->num_channels : 0;
1079         ec->num_channels = num_channels;
1080
1081         for (i = 0; i < num_channels; i++) {
1082                 struct snd_tplg_channel_elem *channel = &enum_ctl->map->channel[i];
1083
1084                 ec->channel[i].size = sizeof(ec->channel[0]);
1085                 ec->channel[i].reg = channel->reg;
1086                 ec->channel[i].shift = channel->shift;
1087                 ec->channel[i].id = channel->id;
1088         }
1089
1090         if (enum_ctl->texts != NULL) {
1091                 struct tplg_elem *texts = tplg_elem_new_common(tplg, NULL,
1092                                                 enum_ctl->hdr.name, SND_TPLG_TYPE_TEXT);
1093
1094                 texts->texts->num_items = num_items;
1095                 for (i = 0; i < num_items; i++) {
1096                         if (!enum_ctl->texts[i])
1097                                 continue;
1098                         snd_strlcpy(ec->texts[i], enum_ctl->texts[i],
1099                                     SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1100                         snd_strlcpy(texts->texts->items[i], enum_ctl->texts[i],
1101                                     SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1102                 }
1103                 tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, enum_ctl->hdr.name);
1104         }
1105
1106         if (enum_ctl->values != NULL) {
1107                 for (i = 0; i < num_items; i++) {
1108                         if (enum_ctl->values[i] == NULL)
1109                                 continue;
1110
1111                         memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE],
1112                                 enum_ctl->values[i],
1113                                 sizeof(int) * ENUM_VAL_SIZE);
1114                 }
1115         }
1116
1117         /* priv data */
1118         priv = enum_ctl->priv;
1119         if (priv && priv->size > 0) {
1120                 ret = tplg_add_data(tplg, elem, priv,
1121                                     sizeof(*priv) + priv->size);
1122                 if (ret < 0)
1123                         return ret;
1124         }
1125
1126         if (e)
1127                 *e = elem;
1128         return 0;
1129 }
1130
1131 int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
1132                    struct tplg_elem **e)
1133 {
1134         struct snd_soc_tplg_bytes_control *be;
1135         struct snd_soc_tplg_private *priv;
1136         struct tplg_elem *elem;
1137         int ret;
1138
1139         tplg_dbg(" Control Bytes: %s", bytes_ctl->hdr.name);
1140
1141         if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
1142                 SNDERR("invalid bytes type %d", bytes_ctl->hdr.type);
1143                 return -EINVAL;
1144         }
1145
1146         elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
1147                 SND_TPLG_TYPE_BYTES);
1148         if (!elem)
1149                 return -ENOMEM;
1150
1151         be = elem->bytes_ext;
1152         be->size = elem->size;
1153         ret = init_ctl_hdr(tplg, elem, &be->hdr, &bytes_ctl->hdr);
1154         if (ret < 0) {
1155                 tplg_elem_free(elem);
1156                 return ret;
1157         }
1158
1159         be->max = bytes_ctl->max;
1160         be->mask = bytes_ctl->mask;
1161         be->base = bytes_ctl->base;
1162         be->num_regs = bytes_ctl->num_regs;
1163         be->ext_ops.put = bytes_ctl->ext_ops.put;
1164         be->ext_ops.get = bytes_ctl->ext_ops.get;
1165
1166         /* priv data */
1167         priv = bytes_ctl->priv;
1168         if (priv && priv->size > 0) {
1169                 ret = tplg_add_data(tplg, elem, priv,
1170                                     sizeof(*priv) + priv->size);
1171                 if (ret < 0)
1172                         return ret;
1173         }
1174
1175         /* check on TLV bytes control */
1176         if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1177                 if ((be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
1178                         != SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
1179                         SNDERR("Invalid TLV bytes control access 0x%x",
1180                                 be->hdr.access);
1181                         tplg_elem_free(elem);
1182                         return -EINVAL;
1183                 }
1184
1185                 if (!be->max) {
1186                         tplg_elem_free(elem);
1187                         return -EINVAL;
1188                 }
1189         }
1190
1191         if (e)
1192                 *e = elem;
1193         return 0;
1194 }
1195
1196 int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1197 {
1198         return tplg_add_mixer(tplg, t->mixer, NULL);
1199 }
1200
1201 int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1202 {
1203         return tplg_add_enum(tplg, t->enum_ctl, NULL);
1204 }
1205
1206 int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1207 {
1208         return tplg_add_bytes(tplg, t->bytes_ctl, NULL);
1209 }
1210
1211 int tplg_decode_control_mixer1(snd_tplg_t *tplg,
1212                                struct list_head *heap,
1213                                struct snd_tplg_mixer_template *mt,
1214                                size_t pos,
1215                                void *bin, size_t size)
1216 {
1217         struct snd_soc_tplg_mixer_control *mc = bin;
1218         struct snd_tplg_channel_map_template *map;
1219         struct snd_tplg_tlv_dbscale_template *db;
1220         int i;
1221
1222         if (size < sizeof(*mc)) {
1223                 SNDERR("mixer: small size %d", size);
1224                 return -EINVAL;
1225         }
1226
1227         tplg_log(tplg, 'D', pos, "mixer: size %d TLV size %d private size %d",
1228                  mc->size, mc->hdr.tlv.size, mc->priv.size);
1229         if (size != mc->size + mc->priv.size) {
1230                 SNDERR("mixer: unexpected element size %d", size);
1231                 return -EINVAL;
1232         }
1233
1234         memset(mt, 0, sizeof(*mt));
1235         mt->hdr.type = mc->hdr.type;
1236         mt->hdr.name = mc->hdr.name;
1237         mt->hdr.access = mc->hdr.access;
1238         mt->hdr.ops.get = mc->hdr.ops.get;
1239         mt->hdr.ops.put = mc->hdr.ops.put;
1240         mt->hdr.ops.info = mc->hdr.ops.info;
1241         mt->min = mc->min;
1242         mt->max = mc->max;
1243         mt->platform_max = mc->platform_max;
1244         tplg_log(tplg, 'D', pos, "mixer: name '%s' access 0x%x",
1245                 mt->hdr.name, mt->hdr.access);
1246         if (mc->num_channels > 0) {
1247                 map = tplg_calloc(heap, sizeof(*map));
1248                 map->num_channels = mc->num_channels;
1249                 for (i = 0; i < map->num_channels; i++) {
1250                         map->channel[i].reg = mc->channel[i].reg;
1251                         map->channel[i].shift = mc->channel[i].shift;
1252                         map->channel[i].id = mc->channel[i].id;
1253                 }
1254                 mt->map = map;
1255         }
1256         if (mc->hdr.tlv.size == 0) {
1257                 /* nothing */
1258         } else if (mc->hdr.tlv.size == sizeof(struct snd_soc_tplg_ctl_tlv)) {
1259                 if (mc->hdr.tlv.type != SNDRV_CTL_TLVT_DB_SCALE) {
1260                         SNDERR("mixer: unknown TLV type %d",
1261                                mc->hdr.tlv.type);
1262                         return -EINVAL;
1263                 }
1264                 db = tplg_calloc(heap, sizeof(*db));
1265                 if (db == NULL)
1266                         return -ENOMEM;
1267                 mt->hdr.tlv_scale = db;
1268                 db->hdr.type = mc->hdr.tlv.type;
1269                 db->min = mc->hdr.tlv.scale.min;
1270                 db->step = mc->hdr.tlv.scale.step;
1271                 db->mute = mc->hdr.tlv.scale.mute;
1272                 tplg_log(tplg, 'D', pos, "mixer: dB scale TLV: min %d step %d mute %d",
1273                          db->min, db->step, db->mute);
1274         } else {
1275                 SNDERR("mixer: wrong TLV size %d", mc->hdr.tlv.size);
1276                 return -EINVAL;
1277         }
1278
1279         mt->priv = &mc->priv;
1280         tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_mixer_control, priv),
1281                  "mixer: private start");
1282         return 0;
1283 }
1284
1285 int tplg_decode_control_mixer(snd_tplg_t *tplg,
1286                               size_t pos,
1287                               struct snd_soc_tplg_hdr *hdr,
1288                               void *bin, size_t size)
1289 {
1290         struct list_head heap;
1291         snd_tplg_obj_template_t t;
1292         struct snd_tplg_mixer_template mt;
1293         struct snd_soc_tplg_mixer_control *mc;
1294         size_t size2;
1295         int err;
1296
1297         err = tplg_decode_template(tplg, pos, hdr, &t);
1298         if (err < 0)
1299                 return err;
1300
1301 next:
1302         if (size < sizeof(*mc)) {
1303                 SNDERR("mixer: small size %d", size);
1304                 return -EINVAL;
1305         }
1306         INIT_LIST_HEAD(&heap);
1307         mc = bin;
1308         size2 = mc->size + mc->priv.size;
1309         if (size2 > size) {
1310                 SNDERR("mixer: wrong element size (%d, priv %d)",
1311                        mc->size, mc->priv.size);
1312                 return -EINVAL;
1313         }
1314
1315         err = tplg_decode_control_mixer1(tplg, &heap, &mt, pos, bin, size2);
1316         if (err >= 0) {
1317                 t.mixer = &mt;
1318                 err = snd_tplg_add_object(tplg, &t);
1319         }
1320         tplg_free(&heap);
1321         if (err < 0)
1322                 return err;
1323
1324         bin += size2;
1325         size -= size2;
1326         pos += size2;
1327
1328         if (size > 0)
1329                 goto next;
1330
1331         return 0;
1332 }
1333
1334 int tplg_decode_control_enum1(snd_tplg_t *tplg,
1335                               struct list_head *heap,
1336                               struct snd_tplg_enum_template *et,
1337                               size_t pos,
1338                               struct snd_soc_tplg_enum_control *ec)
1339 {
1340         int i;
1341
1342         if (ec->num_channels > SND_TPLG_MAX_CHAN ||
1343             ec->num_channels > SND_SOC_TPLG_MAX_CHAN) {
1344                 SNDERR("enum: unexpected channel count %d", ec->num_channels);
1345                 return -EINVAL;
1346         }
1347         if (ec->items > SND_SOC_TPLG_NUM_TEXTS) {
1348                 SNDERR("enum: unexpected texts count %d", ec->items);
1349                 return -EINVAL;
1350         }
1351
1352         memset(et, 0, sizeof(*et));
1353         et->hdr.type = ec->hdr.type;
1354         et->hdr.name = ec->hdr.name;
1355         et->hdr.access = ec->hdr.access;
1356         et->hdr.ops.get = ec->hdr.ops.get;
1357         et->hdr.ops.put = ec->hdr.ops.put;
1358         et->hdr.ops.info = ec->hdr.ops.info;
1359         et->mask = ec->mask;
1360
1361         if (ec->items > 0) {
1362                 et->items = ec->items;
1363                 et->texts = tplg_calloc(heap, sizeof(char *) * ec->items);
1364                 if (!et->texts)
1365                         return -ENOMEM;
1366                 for (i = 0; (unsigned int)i < ec->items; i++)
1367                         et->texts[i] = ec->texts[i];
1368         }
1369
1370         et->map = tplg_calloc(heap, sizeof(struct snd_tplg_channel_map_template));
1371         if (!et->map)
1372                 return -ENOMEM;
1373         et->map->num_channels = ec->num_channels;
1374         for (i = 0; i < et->map->num_channels; i++) {
1375                 struct snd_tplg_channel_elem *channel = &et->map->channel[i];
1376
1377                 tplg_log(tplg, 'D', pos + ((void *)&ec->channel[i] - (void *)ec),
1378                          "enum: channel size %d", ec->channel[i].size);
1379                 channel->reg = ec->channel[i].reg;
1380                 channel->shift = ec->channel[i].shift;
1381                 channel->id = ec->channel[i].id;
1382         }
1383
1384         et->priv = &ec->priv;
1385         return 0;
1386 }
1387
1388 int tplg_decode_control_enum(snd_tplg_t *tplg,
1389                              size_t pos,
1390                              struct snd_soc_tplg_hdr *hdr,
1391                              void *bin, size_t size)
1392 {
1393         struct list_head heap;
1394         snd_tplg_obj_template_t t;
1395         struct snd_tplg_enum_template et;
1396         struct snd_soc_tplg_enum_control *ec;
1397         size_t size2;
1398         int err;
1399
1400         err = tplg_decode_template(tplg, pos, hdr, &t);
1401         if (err < 0)
1402                 return err;
1403
1404 next:
1405         if (size < sizeof(*ec)) {
1406                 SNDERR("enum: small size %d", size);
1407                 return -EINVAL;
1408         }
1409         INIT_LIST_HEAD(&heap);
1410         ec = bin;
1411         size2 = ec->size + ec->priv.size;
1412         if (size2 > size) {
1413                 SNDERR("enum: wrong element size (%d, priv %d)",
1414                        ec->size, ec->priv.size);
1415                 return -EINVAL;
1416         }
1417
1418         tplg_log(tplg, 'D', pos, "enum: size %d private size %d",
1419                  ec->size, ec->priv.size);
1420
1421         err = tplg_decode_control_enum1(tplg, &heap, &et, pos, ec);
1422         if (err >= 0) {
1423                 t.enum_ctl = &et;
1424                 err = snd_tplg_add_object(tplg, &t);
1425         }
1426         tplg_free(&heap);
1427         if (err < 0)
1428                 return err;
1429
1430         bin += size2;
1431         size -= size2;
1432         pos += size2;
1433
1434         if (size > 0)
1435                 goto next;
1436
1437         return 0;
1438 }
1439
1440 int tplg_decode_control_bytes1(snd_tplg_t *tplg,
1441                                struct snd_tplg_bytes_template *bt,
1442                                size_t pos,
1443                                void *bin, size_t size)
1444 {
1445         struct snd_soc_tplg_bytes_control *bc = bin;
1446
1447         if (size < sizeof(*bc)) {
1448                 SNDERR("bytes: small size %d", size);
1449                 return -EINVAL;
1450         }
1451
1452         tplg_log(tplg, 'D', pos, "control bytes: size %d private size %d",
1453                  bc->size, bc->priv.size);
1454         if (size != bc->size + bc->priv.size) {
1455                 SNDERR("bytes: unexpected element size %d", size);
1456                 return -EINVAL;
1457         }
1458
1459         memset(bt, 0, sizeof(*bt));
1460         bt->hdr.type = bc->hdr.type;
1461         bt->hdr.name = bc->hdr.name;
1462         bt->hdr.access = bc->hdr.access;
1463         bt->hdr.ops.get = bc->hdr.ops.get;
1464         bt->hdr.ops.put = bc->hdr.ops.put;
1465         bt->hdr.ops.info = bc->hdr.ops.info;
1466         bt->max = bc->max;
1467         bt->mask = bc->mask;
1468         bt->base = bc->base;
1469         bt->num_regs = bc->num_regs;
1470         bt->ext_ops.get = bc->ext_ops.get;
1471         bt->ext_ops.put = bc->ext_ops.put;
1472         bt->ext_ops.info = bc->ext_ops.info;
1473         tplg_log(tplg, 'D', pos, "control bytes: name '%s' access 0x%x",
1474                  bt->hdr.name, bt->hdr.access);
1475
1476         bt->priv = &bc->priv;
1477         return 0;
1478 }
1479
1480 int tplg_decode_control_bytes(snd_tplg_t *tplg,
1481                               size_t pos,
1482                               struct snd_soc_tplg_hdr *hdr,
1483                               void *bin, size_t size)
1484 {
1485         snd_tplg_obj_template_t t;
1486         struct snd_tplg_bytes_template bt;
1487         struct snd_soc_tplg_bytes_control *bc;
1488         size_t size2;
1489         int err;
1490
1491         err = tplg_decode_template(tplg, pos, hdr, &t);
1492         if (err < 0)
1493                 return err;
1494
1495 next:
1496         if (size < sizeof(*bc)) {
1497                 SNDERR("bytes: small size %d", size);
1498                 return -EINVAL;
1499         }
1500         bc = bin;
1501         size2 = bc->size + bc->priv.size;
1502         if (size2 > size) {
1503                 SNDERR("bytes: wrong element size (%d, priv %d)",
1504                        bc->size, bc->priv.size);
1505                 return -EINVAL;
1506         }
1507
1508         err = tplg_decode_control_bytes1(tplg, &bt, pos, bin, size);
1509         if (err < 0)
1510                 return err;
1511
1512         t.bytes_ctl = &bt;
1513         err = snd_tplg_add_object(tplg, &t);
1514         if (err < 0)
1515                 return err;
1516
1517         bin += size2;
1518         size -= size2;
1519         pos += size2;
1520
1521         if (size > 0)
1522                 goto next;
1523
1524         return 0;
1525 }