2 Copyright(c) 2014-2015 Intel Corporation
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.
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.
15 Authors: Mengdong Lin <mengdong.lin@intel.com>
16 Yao Jin <yao.jin@intel.com>
17 Liam Girdwood <liam.r.girdwood@linux.intel.com>
21 #include "tplg_local.h"
23 #define ENUM_VAL_SIZE (SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2)
25 struct ctl_access_elem {
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},
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)
51 snd_config_iterator_t i, next;
53 const char *value = NULL;
58 snd_config_for_each(i, next, cfg) {
59 n = snd_config_iterator_entry(i);
62 if (snd_config_get_string(n, &value) < 0)
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);
79 int parse_access(snd_config_t *cfg,
80 struct snd_soc_tplg_ctl_hdr *hdr)
82 snd_config_iterator_t i, next;
87 snd_config_for_each(i, next, cfg) {
89 n = snd_config_iterator_entry(i);
90 if (snd_config_get_id(n, &id) < 0)
93 if (strcmp(id, "access") == 0) {
94 err = parse_access_values(n, hdr);
96 SNDERR("failed to parse access");
107 static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
108 struct snd_soc_tplg_ctl_hdr *hdr, char **dst,
112 unsigned int j, count, access, cval;
115 if (hdr->access == 0)
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) {
123 last = ctl_access[j].name;
128 return tplg_save_printf(dst, pfx, "access.0 %s\n", last);
129 err = tplg_save_printf(dst, pfx, "access [\n");
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",
143 return tplg_save_printf(dst, pfx, "]\n");
146 /* copy referenced TLV to the mixer control */
147 static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
149 struct snd_soc_tplg_mixer_control *mixer_ctrl = elem->mixer_ctrl;
150 struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
152 tplg_dbg("TLV '%s' used by '%s", ref->id, elem->id);
154 /* TLV has a fixed size */
155 mixer_ctrl->hdr.tlv = *tlv;
159 /* check referenced TLV for a mixer control */
160 static int tplg_build_mixer_control(snd_tplg_t *tplg,
161 struct tplg_elem *elem)
163 struct tplg_ref *ref;
164 struct list_head *base, *pos;
167 base = &elem->ref_list;
169 /* for each ref in this control elem */
170 list_for_each(pos, base) {
172 ref = list_entry(pos, struct tplg_ref, list);
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);
180 err = copy_tlv(elem, ref->elem);
182 } else if (ref->type == SND_TPLG_TYPE_DATA) {
183 err = tplg_copy_data(tplg, elem, ref);
189 SNDERR("cannot find '%s' referenced by"
190 " control '%s'", ref->id, elem->id);
199 static void copy_enum_texts(struct tplg_elem *enum_elem,
200 struct tplg_elem *ref_elem)
202 struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
203 struct tplg_texts *texts = ref_elem->texts;
205 memcpy(ec->texts, texts->items,
206 SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
207 ec->items += texts->num_items;
210 /* check referenced text for a enum control */
211 static int tplg_build_enum_control(snd_tplg_t *tplg,
212 struct tplg_elem *elem)
214 struct tplg_ref *ref;
215 struct list_head *base, *pos;
218 base = &elem->ref_list;
220 list_for_each(pos, base) {
222 ref = list_entry(pos, struct tplg_ref, list);
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);
230 copy_enum_texts(elem, ref->elem);
232 } else if (ref->type == SND_TPLG_TYPE_DATA) {
233 err = tplg_copy_data(tplg, elem, ref);
238 SNDERR("cannot find '%s' referenced by"
239 " control '%s'", ref->id, elem->id);
247 /* check referenced private data for a byte control */
248 static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
250 struct tplg_ref *ref;
251 struct list_head *base, *pos;
254 base = &elem->ref_list;
256 list_for_each(pos, base) {
258 ref = list_entry(pos, struct tplg_ref, list);
262 if (ref->type == SND_TPLG_TYPE_DATA) {
263 err = tplg_copy_data(tplg, elem, ref);
272 int tplg_build_controls(snd_tplg_t *tplg)
274 struct list_head *base, *pos;
275 struct tplg_elem *elem;
278 base = &tplg->mixer_list;
279 list_for_each(pos, base) {
281 elem = list_entry(pos, struct tplg_elem, list);
282 err = tplg_build_mixer_control(tplg, elem);
286 /* add control to manifest */
287 tplg->manifest.control_elems++;
290 base = &tplg->enum_list;
291 list_for_each(pos, base) {
293 elem = list_entry(pos, struct tplg_elem, list);
294 err = tplg_build_enum_control(tplg, elem);
298 /* add control to manifest */
299 tplg->manifest.control_elems++;
302 base = &tplg->bytes_ext_list;
303 list_for_each(pos, base) {
305 elem = list_entry(pos, struct tplg_elem, list);
306 err = tplg_build_bytes_control(tplg, elem);
310 /* add control to manifest */
311 tplg->manifest.control_elems++;
319 * Parse TLV of DBScale type.
321 * Parse DBScale describing min, step, mute in DB.
323 static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem)
325 snd_config_iterator_t i, next;
327 struct snd_soc_tplg_ctl_tlv *tplg_tlv = elem->tlv;
328 struct snd_soc_tplg_tlv_dbscale *scale;
329 const char *id = NULL;
332 tplg_dbg(" scale: %s", elem->id);
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;
338 snd_config_for_each(i, next, cfg) {
340 n = snd_config_iterator_entry(i);
343 if (snd_config_get_id(n, &id) < 0)
347 if (tplg_get_integer(n, &val, 0))
350 tplg_dbg("\t%s = %i", id, val);
353 if (strcmp(id, "min") == 0)
355 else if (strcmp(id, "step") == 0)
357 else if (strcmp(id, "mute") == 0)
360 SNDERR("unknown id '%s'", id);
367 int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
368 void *private ATTRIBUTE_UNUSED)
370 snd_config_iterator_t i, next;
374 struct tplg_elem *elem;
376 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV);
380 snd_config_for_each(i, next, cfg) {
382 n = snd_config_iterator_entry(i);
383 if (snd_config_get_id(n, &id) < 0)
386 if (strcmp(id, "scale") == 0) {
387 err = tplg_parse_tlv_dbscale(n, elem);
389 SNDERR("failed to DBScale");
400 int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
401 struct tplg_elem *elem,
402 char **dst, const char *pfx)
404 struct snd_soc_tplg_ctl_tlv *tlv = elem->tlv;
405 struct snd_soc_tplg_tlv_dbscale *scale;
408 if (tlv->type != SNDRV_CTL_TLVT_DB_SCALE) {
409 SNDERR("unknown TLV type");
414 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
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);
424 err = tplg_save_printf(dst, pfx, "\t}\n");
426 err = tplg_save_printf(dst, pfx, "}\n");
430 /* Parse Control Bytes */
431 int tplg_parse_control_bytes(snd_tplg_t *tplg,
433 void *private ATTRIBUTE_UNUSED)
435 struct snd_soc_tplg_bytes_control *be;
436 struct tplg_elem *elem;
437 snd_config_iterator_t i, next;
439 const char *id, *val = NULL;
441 bool access_set = false, tlv_set = false;
443 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES);
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;
452 tplg_dbg(" Control Bytes: %s", elem->id);
454 snd_config_for_each(i, next, cfg) {
455 n = snd_config_iterator_entry(i);
456 if (snd_config_get_id(n, &id) < 0)
460 if (strcmp(id, "comment") == 0)
465 if (strcmp(id, "base") == 0) {
466 if (tplg_get_integer(n, &ival, 0))
470 tplg_dbg("\t%s: %d", id, be->base);
474 if (strcmp(id, "num_regs") == 0) {
475 if (tplg_get_integer(n, &ival, 0))
479 tplg_dbg("\t%s: %d", id, be->num_regs);
483 if (strcmp(id, "max") == 0) {
484 if (tplg_get_integer(n, &ival, 0))
488 tplg_dbg("\t%s: %d", id, be->max);
492 if (strcmp(id, "mask") == 0) {
493 if (tplg_get_integer(n, &ival, 16))
497 tplg_dbg("\t%s: %d", id, be->mask);
501 if (strcmp(id, "data") == 0) {
502 err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
508 if (strcmp(id, "tlv") == 0) {
509 if (snd_config_get_string(n, &val) < 0)
512 err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
517 tplg_dbg("\t%s: %s", id, val);
521 if (strcmp(id, "ops") == 0) {
522 err = tplg_parse_compound(tplg, n, tplg_parse_ops,
529 if (strcmp(id, "extops") == 0) {
530 err = tplg_parse_compound(tplg, n, tplg_parse_ext_ops,
537 if (strcmp(id, "access") == 0) {
538 err = parse_access(cfg, &be->hdr);
546 /* set CTL access to default values if none are provided */
549 be->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
551 be->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
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)
562 struct snd_soc_tplg_bytes_control *be = elem->bytes_ext;
569 snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
570 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
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);
584 err = tplg_save_ops(tplg, &be->hdr, dst, pfx2);
586 err = tplg_save_ext_ops(tplg, be, dst, pfx2);
588 err = tplg_save_access(tplg, &be->hdr, dst, pfx2);
590 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
593 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
596 err = tplg_save_printf(dst, pfx, "}\n");
600 /* Parse Control Enums. */
601 int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
602 void *private ATTRIBUTE_UNUSED)
604 struct snd_soc_tplg_enum_control *ec;
605 struct tplg_elem *elem;
606 snd_config_iterator_t i, next;
608 const char *id, *val = NULL;
610 bool access_set = false;
612 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM);
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;
622 /* set channel reg to default state */
623 for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++) {
624 ec->channel[j].reg = -1;
627 tplg_dbg(" Control Enum: %s", elem->id);
629 snd_config_for_each(i, next, cfg) {
631 n = snd_config_iterator_entry(i);
632 if (snd_config_get_id(n, &id) < 0)
636 if (strcmp(id, "comment") == 0)
641 if (strcmp(id, "texts") == 0) {
642 if (snd_config_get_string(n, &val) < 0)
645 tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val);
646 tplg_dbg("\t%s: %s", id, val);
650 if (strcmp(id, "channel") == 0) {
651 if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
652 SNDERR("too many channels %s", elem->id);
656 err = tplg_parse_compound(tplg, n, tplg_parse_channel,
661 ec->num_channels = tplg->channel_idx;
665 if (strcmp(id, "ops") == 0) {
666 err = tplg_parse_compound(tplg, n, tplg_parse_ops,
673 if (strcmp(id, "data") == 0) {
674 err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
680 if (strcmp(id, "access") == 0) {
681 err = parse_access(cfg, &ec->hdr);
689 /* set CTL access to default values if none are provided */
691 ec->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
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)
702 struct snd_soc_tplg_enum_control *ec = elem->enum_ctrl;
709 snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
710 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
713 if (err >= 0 && elem->index > 0)
714 err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
716 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TEXT,
719 err = tplg_save_channels(tplg, ec->channel, ec->num_channels,
722 err = tplg_save_ops(tplg, &ec->hdr, dst, pfx2);
724 err = tplg_save_access(tplg, &ec->hdr, dst, pfx2);
726 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
729 err = tplg_save_printf(dst, pfx, "}\n");
735 * Mixer control. Supports multiple channels.
737 int tplg_parse_control_mixer(snd_tplg_t *tplg,
739 void *private ATTRIBUTE_UNUSED)
741 struct snd_soc_tplg_mixer_control *mc;
742 struct tplg_elem *elem;
743 snd_config_iterator_t i, next;
745 const char *id, *val = NULL;
747 bool access_set = false, tlv_set = false;
749 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_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;
760 /* set channel reg to default state */
761 for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
762 mc->channel[j].reg = -1;
764 tplg_dbg(" Control Mixer: %s", elem->id);
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)
773 if (strcmp(id, "comment") == 0)
778 if (strcmp(id, "channel") == 0) {
779 if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
780 SNDERR("too many channels %s", elem->id);
784 err = tplg_parse_compound(tplg, n, tplg_parse_channel,
789 mc->num_channels = tplg->channel_idx;
793 if (strcmp(id, "max") == 0) {
794 if (tplg_get_integer(n, &ival, 0))
798 tplg_dbg("\t%s: %d", id, mc->max);
802 if (strcmp(id, "invert") == 0) {
803 ival = snd_config_get_bool(n);
808 tplg_dbg("\t%s: %d", id, mc->invert);
812 if (strcmp(id, "ops") == 0) {
813 err = tplg_parse_compound(tplg, n, tplg_parse_ops,
820 if (strcmp(id, "tlv") == 0) {
821 if (snd_config_get_string(n, &val) < 0)
824 err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
829 tplg_dbg("\t%s: %s", id, val);
833 if (strcmp(id, "data") == 0) {
834 err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
840 if (strcmp(id, "access") == 0) {
841 err = parse_access(cfg, &mc->hdr);
849 /* set CTL access to default values if none are provided */
852 mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
854 mc->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
860 int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
861 struct tplg_elem *elem, char **dst,
864 struct snd_soc_tplg_mixer_control *mc = elem->mixer_ctrl;
870 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
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);
877 err = tplg_save_channels(tplg, mc->channel, mc->num_channels,
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);
886 err = tplg_save_ops(tplg, &mc->hdr, dst, pfx2);
888 err = tplg_save_access(tplg, &mc->hdr, dst, pfx2);
890 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
893 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
896 err = tplg_save_printf(dst, pfx, "}\n");
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)
905 struct tplg_elem *elem;
908 hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr);
911 snd_strlcpy(hdr->name, t->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
913 /* clean up access flag */
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);
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;
929 if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
930 && !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
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;
938 SNDERR("missing TLV data");
942 elem = tplg_elem_new_common(tplg, NULL, parent->id,
949 err = tplg_ref_add(parent, SND_TPLG_TYPE_TLV, parent->id);
953 tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
954 tlv->type = tlvt->type;
956 switch (tlvt->type) {
957 case SNDRV_CTL_TLVT_DB_SCALE:
958 scalet = container_of(tlvt,
959 struct snd_tplg_tlv_dbscale_template, hdr);
961 scale->min = scalet->min;
962 scale->step = scalet->step;
963 scale->mute = scalet->mute;
966 /* TODO: add support for other TLV types */
968 SNDERR("unsupported TLV type %d", tlv->type);
976 int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
977 struct tplg_elem **e)
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;
984 tplg_dbg(" Control Mixer: %s", mixer->hdr.name);
986 if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) {
987 SNDERR("invalid mixer type %d", mixer->hdr.type);
991 elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name,
992 SND_TPLG_TYPE_MIXER);
997 mc = elem->mixer_ctrl;
998 mc->size = elem->size;
999 ret = init_ctl_hdr(tplg, elem, &mc->hdr, &mixer->hdr);
1001 tplg_elem_free(elem);
1005 mc->min = mixer->min;
1006 mc->max = mixer->max;
1007 mc->platform_max = mixer->platform_max;
1008 mc->invert = mixer->invert;
1010 /* set channel reg to default state */
1011 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
1012 mc->channel[i].reg = -1;
1014 num_channels = mixer->map ? mixer->map->num_channels : 0;
1015 mc->num_channels = num_channels;
1017 for (i = 0; i < num_channels; i++) {
1018 struct snd_tplg_channel_elem *channel = &mixer->map->channel[i];
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;
1028 if (priv && priv->size > 0) {
1029 ret = tplg_add_data(tplg, elem, priv,
1030 sizeof(*priv) + priv->size);
1040 int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
1041 struct tplg_elem **e)
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;
1048 tplg_dbg(" Control Enum: %s", enum_ctl->hdr.name);
1050 if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) {
1051 SNDERR("invalid enum type %d", enum_ctl->hdr.type);
1055 elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name,
1056 SND_TPLG_TYPE_ENUM);
1060 ec = elem->enum_ctrl;
1061 ec->size = elem->size;
1062 ret = init_ctl_hdr(tplg, elem, &ec->hdr, &enum_ctl->hdr);
1064 tplg_elem_free(elem);
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;
1074 /* set channel reg to default state */
1075 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
1076 ec->channel[i].reg = -1;
1078 num_channels = enum_ctl->map ? enum_ctl->map->num_channels : 0;
1079 ec->num_channels = num_channels;
1081 for (i = 0; i < num_channels; i++) {
1082 struct snd_tplg_channel_elem *channel = &enum_ctl->map->channel[i];
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;
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);
1094 texts->texts->num_items = num_items;
1095 for (i = 0; i < num_items; i++) {
1096 if (!enum_ctl->texts[i])
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);
1103 tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, enum_ctl->hdr.name);
1106 if (enum_ctl->values != NULL) {
1107 for (i = 0; i < num_items; i++) {
1108 if (enum_ctl->values[i] == NULL)
1111 memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE],
1112 enum_ctl->values[i],
1113 sizeof(int) * ENUM_VAL_SIZE);
1118 priv = enum_ctl->priv;
1119 if (priv && priv->size > 0) {
1120 ret = tplg_add_data(tplg, elem, priv,
1121 sizeof(*priv) + priv->size);
1131 int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
1132 struct tplg_elem **e)
1134 struct snd_soc_tplg_bytes_control *be;
1135 struct snd_soc_tplg_private *priv;
1136 struct tplg_elem *elem;
1139 tplg_dbg(" Control Bytes: %s", bytes_ctl->hdr.name);
1141 if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
1142 SNDERR("invalid bytes type %d", bytes_ctl->hdr.type);
1146 elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
1147 SND_TPLG_TYPE_BYTES);
1151 be = elem->bytes_ext;
1152 be->size = elem->size;
1153 ret = init_ctl_hdr(tplg, elem, &be->hdr, &bytes_ctl->hdr);
1155 tplg_elem_free(elem);
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;
1167 priv = bytes_ctl->priv;
1168 if (priv && priv->size > 0) {
1169 ret = tplg_add_data(tplg, elem, priv,
1170 sizeof(*priv) + priv->size);
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",
1181 tplg_elem_free(elem);
1186 tplg_elem_free(elem);
1196 int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1198 return tplg_add_mixer(tplg, t->mixer, NULL);
1201 int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1203 return tplg_add_enum(tplg, t->enum_ctl, NULL);
1206 int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1208 return tplg_add_bytes(tplg, t->bytes_ctl, NULL);
1211 int tplg_decode_control_mixer1(snd_tplg_t *tplg,
1212 struct list_head *heap,
1213 struct snd_tplg_mixer_template *mt,
1215 void *bin, size_t size)
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;
1222 if (size < sizeof(*mc)) {
1223 SNDERR("mixer: small size %d", size);
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);
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;
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;
1256 if (mc->hdr.tlv.size == 0) {
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",
1264 db = tplg_calloc(heap, sizeof(*db));
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);
1275 SNDERR("mixer: wrong TLV size %d", mc->hdr.tlv.size);
1279 mt->priv = &mc->priv;
1280 tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_mixer_control, priv),
1281 "mixer: private start");
1285 int tplg_decode_control_mixer(snd_tplg_t *tplg,
1287 struct snd_soc_tplg_hdr *hdr,
1288 void *bin, size_t size)
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;
1297 err = tplg_decode_template(tplg, pos, hdr, &t);
1302 if (size < sizeof(*mc)) {
1303 SNDERR("mixer: small size %d", size);
1306 INIT_LIST_HEAD(&heap);
1308 size2 = mc->size + mc->priv.size;
1310 SNDERR("mixer: wrong element size (%d, priv %d)",
1311 mc->size, mc->priv.size);
1315 err = tplg_decode_control_mixer1(tplg, &heap, &mt, pos, bin, size2);
1318 err = snd_tplg_add_object(tplg, &t);
1334 int tplg_decode_control_enum1(snd_tplg_t *tplg,
1335 struct list_head *heap,
1336 struct snd_tplg_enum_template *et,
1338 struct snd_soc_tplg_enum_control *ec)
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);
1347 if (ec->items > SND_SOC_TPLG_NUM_TEXTS) {
1348 SNDERR("enum: unexpected texts count %d", ec->items);
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;
1361 if (ec->items > 0) {
1362 et->items = ec->items;
1363 et->texts = tplg_calloc(heap, sizeof(char *) * ec->items);
1366 for (i = 0; (unsigned int)i < ec->items; i++)
1367 et->texts[i] = ec->texts[i];
1370 et->map = tplg_calloc(heap, sizeof(struct snd_tplg_channel_map_template));
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];
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;
1384 et->priv = &ec->priv;
1388 int tplg_decode_control_enum(snd_tplg_t *tplg,
1390 struct snd_soc_tplg_hdr *hdr,
1391 void *bin, size_t size)
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;
1400 err = tplg_decode_template(tplg, pos, hdr, &t);
1405 if (size < sizeof(*ec)) {
1406 SNDERR("enum: small size %d", size);
1409 INIT_LIST_HEAD(&heap);
1411 size2 = ec->size + ec->priv.size;
1413 SNDERR("enum: wrong element size (%d, priv %d)",
1414 ec->size, ec->priv.size);
1418 tplg_log(tplg, 'D', pos, "enum: size %d private size %d",
1419 ec->size, ec->priv.size);
1421 err = tplg_decode_control_enum1(tplg, &heap, &et, pos, ec);
1424 err = snd_tplg_add_object(tplg, &t);
1440 int tplg_decode_control_bytes1(snd_tplg_t *tplg,
1441 struct snd_tplg_bytes_template *bt,
1443 void *bin, size_t size)
1445 struct snd_soc_tplg_bytes_control *bc = bin;
1447 if (size < sizeof(*bc)) {
1448 SNDERR("bytes: small size %d", size);
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);
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;
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);
1476 bt->priv = &bc->priv;
1480 int tplg_decode_control_bytes(snd_tplg_t *tplg,
1482 struct snd_soc_tplg_hdr *hdr,
1483 void *bin, size_t size)
1485 snd_tplg_obj_template_t t;
1486 struct snd_tplg_bytes_template bt;
1487 struct snd_soc_tplg_bytes_control *bc;
1491 err = tplg_decode_template(tplg, pos, hdr, &t);
1496 if (size < sizeof(*bc)) {
1497 SNDERR("bytes: small size %d", size);
1501 size2 = bc->size + bc->priv.size;
1503 SNDERR("bytes: wrong element size (%d, priv %d)",
1504 bc->size, bc->priv.size);
1508 err = tplg_decode_control_bytes1(tplg, &bt, pos, bin, size);
1513 err = snd_tplg_add_object(tplg, &t);