2 Copyright(c) 2014-2015 Intel Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of version 2 of the GNU General Public License as
7 published by the Free Software Foundation.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 Authors: Mengdong Lin <mengdong.lin@intel.com>
15 Yao Jin <yao.jin@intel.com>
16 Liam Girdwood <liam.r.girdwood@linux.intel.com>
20 #include "tplg_local.h"
22 #define ENUM_VAL_SIZE (SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2)
24 struct ctl_access_elem {
29 /* CTL access strings and codes */
30 static const struct ctl_access_elem ctl_access[] = {
31 {"read", SNDRV_CTL_ELEM_ACCESS_READ},
32 {"write", SNDRV_CTL_ELEM_ACCESS_WRITE},
33 {"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE},
34 {"volatile", SNDRV_CTL_ELEM_ACCESS_VOLATILE},
35 {"timestamp", SNDRV_CTL_ELEM_ACCESS_TIMESTAMP},
36 {"tlv_read", SNDRV_CTL_ELEM_ACCESS_TLV_READ},
37 {"tlv_write", SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
38 {"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE},
39 {"tlv_command", SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
40 {"inactive", SNDRV_CTL_ELEM_ACCESS_INACTIVE},
41 {"lock", SNDRV_CTL_ELEM_ACCESS_LOCK},
42 {"owner", SNDRV_CTL_ELEM_ACCESS_OWNER},
43 {"tlv_callback", SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK},
44 {"user", SNDRV_CTL_ELEM_ACCESS_USER},
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;
56 tplg_dbg(" Access:\n");
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\n", 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("error: failed to parse access");
106 /* copy referenced TLV to the mixer control */
107 static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
109 struct snd_soc_tplg_mixer_control *mixer_ctrl = elem->mixer_ctrl;
110 struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
112 tplg_dbg("TLV '%s' used by '%s\n", ref->id, elem->id);
114 /* TLV has a fixed size */
115 mixer_ctrl->hdr.tlv = *tlv;
119 /* check referenced TLV for a mixer control */
120 static int tplg_build_mixer_control(snd_tplg_t *tplg,
121 struct tplg_elem *elem)
123 struct tplg_ref *ref;
124 struct list_head *base, *pos;
127 base = &elem->ref_list;
129 /* for each ref in this control elem */
130 list_for_each(pos, base) {
132 ref = list_entry(pos, struct tplg_ref, list);
133 if (ref->id == NULL || ref->elem)
136 if (ref->type == SND_TPLG_TYPE_TLV) {
137 ref->elem = tplg_elem_lookup(&tplg->tlv_list,
138 ref->id, SND_TPLG_TYPE_TLV);
140 err = copy_tlv(elem, ref->elem);
142 } else if (ref->type == SND_TPLG_TYPE_DATA) {
143 ref->elem = tplg_elem_lookup(&tplg->pdata_list,
144 ref->id, SND_TPLG_TYPE_DATA);
145 err = tplg_copy_data(elem, ref->elem);
149 SNDERR("error: cannot find '%s' referenced by"
150 " control '%s'\n", ref->id, elem->id);
159 static void copy_enum_texts(struct tplg_elem *enum_elem,
160 struct tplg_elem *ref_elem)
162 struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
164 memcpy(ec->texts, ref_elem->texts,
165 SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
168 /* check referenced text for a enum control */
169 static int tplg_build_enum_control(snd_tplg_t *tplg,
170 struct tplg_elem *elem)
172 struct tplg_ref *ref;
173 struct list_head *base, *pos;
176 base = &elem->ref_list;
178 list_for_each(pos, base) {
180 ref = list_entry(pos, struct tplg_ref, list);
181 if (ref->id == NULL || ref->elem)
184 if (ref->type == SND_TPLG_TYPE_TEXT) {
185 ref->elem = tplg_elem_lookup(&tplg->text_list,
186 ref->id, SND_TPLG_TYPE_TEXT);
188 copy_enum_texts(elem, ref->elem);
190 } else if (ref->type == SND_TPLG_TYPE_DATA) {
191 ref->elem = tplg_elem_lookup(&tplg->pdata_list,
192 ref->id, SND_TPLG_TYPE_DATA);
193 err = tplg_copy_data(elem, ref->elem);
196 SNDERR("error: cannot find '%s' referenced by"
197 " control '%s'\n", ref->id, elem->id);
206 /* check referenced private data for a byte control */
207 static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
209 struct tplg_ref *ref;
210 struct list_head *base, *pos;
212 base = &elem->ref_list;
214 list_for_each(pos, base) {
216 ref = list_entry(pos, struct tplg_ref, list);
217 if (ref->id == NULL || ref->elem)
220 /* bytes control only reference one private data section */
221 ref->elem = tplg_elem_lookup(&tplg->pdata_list,
222 ref->id, SND_TPLG_TYPE_DATA);
224 SNDERR("error: cannot find data '%s'"
225 " referenced by control '%s'\n",
230 /* copy texts to enum elem */
231 return tplg_copy_data(elem, ref->elem);
237 int tplg_build_controls(snd_tplg_t *tplg)
239 struct list_head *base, *pos;
240 struct tplg_elem *elem;
243 base = &tplg->mixer_list;
244 list_for_each(pos, base) {
246 elem = list_entry(pos, struct tplg_elem, list);
247 err = tplg_build_mixer_control(tplg, elem);
251 /* add control to manifest */
252 tplg->manifest.control_elems++;
255 base = &tplg->enum_list;
256 list_for_each(pos, base) {
258 elem = list_entry(pos, struct tplg_elem, list);
259 err = tplg_build_enum_control(tplg, elem);
263 /* add control to manifest */
264 tplg->manifest.control_elems++;
267 base = &tplg->bytes_ext_list;
268 list_for_each(pos, base) {
270 elem = list_entry(pos, struct tplg_elem, list);
271 err = tplg_build_bytes_control(tplg, elem);
275 /* add control to manifest */
276 tplg->manifest.control_elems++;
284 * Parse TLV of DBScale type.
286 * Parse DBScale describing min, step, mute in DB.
288 static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem)
290 snd_config_iterator_t i, next;
292 struct snd_soc_tplg_ctl_tlv *tplg_tlv;
293 struct snd_soc_tplg_tlv_dbscale *scale;
294 const char *id = NULL, *value = NULL;
296 tplg_dbg(" scale: %s\n", elem->id);
298 tplg_tlv = calloc(1, sizeof(*tplg_tlv));
302 elem->tlv = tplg_tlv;
303 tplg_tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
304 tplg_tlv->type = SNDRV_CTL_TLVT_DB_SCALE;
305 scale = &tplg_tlv->scale;
307 snd_config_for_each(i, next, cfg) {
309 n = snd_config_iterator_entry(i);
312 if (snd_config_get_id(n, &id) < 0) {
313 SNDERR("error: cant get ID\n");
318 if (snd_config_get_string(n, &value) < 0)
321 tplg_dbg("\t%s = %s\n", id, value);
324 if (strcmp(id, "min") == 0)
325 scale->min = atoi(value);
326 else if (strcmp(id, "step") == 0)
327 scale->step = atoi(value);
328 else if (strcmp(id, "mute") == 0)
329 scale->mute = atoi(value);
331 SNDERR("error: unknown key %s\n", id);
338 int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
339 void *private ATTRIBUTE_UNUSED)
341 snd_config_iterator_t i, next;
345 struct tplg_elem *elem;
347 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV);
351 snd_config_for_each(i, next, cfg) {
353 n = snd_config_iterator_entry(i);
354 if (snd_config_get_id(n, &id) < 0)
357 if (strcmp(id, "scale") == 0) {
358 err = tplg_parse_tlv_dbscale(n, elem);
360 SNDERR("error: failed to DBScale");
370 /* Parse Control Bytes */
371 int tplg_parse_control_bytes(snd_tplg_t *tplg,
372 snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
374 struct snd_soc_tplg_bytes_control *be;
375 struct tplg_elem *elem;
376 snd_config_iterator_t i, next;
378 const char *id, *val = NULL;
380 bool access_set = false, tlv_set = false;
382 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES);
386 be = elem->bytes_ext;
387 be->size = elem->size;
388 elem_copy_text(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
389 be->hdr.type = SND_SOC_TPLG_TYPE_BYTES;
391 tplg_dbg(" Control Bytes: %s\n", elem->id);
393 snd_config_for_each(i, next, cfg) {
394 n = snd_config_iterator_entry(i);
395 if (snd_config_get_id(n, &id) < 0)
399 if (strcmp(id, "comment") == 0)
404 if (strcmp(id, "index") == 0) {
405 if (snd_config_get_string(n, &val) < 0)
408 elem->index = atoi(val);
409 tplg_dbg("\t%s: %d\n", id, elem->index);
413 if (strcmp(id, "base") == 0) {
414 if (snd_config_get_string(n, &val) < 0)
417 be->base = atoi(val);
418 tplg_dbg("\t%s: %d\n", id, be->base);
422 if (strcmp(id, "num_regs") == 0) {
423 if (snd_config_get_string(n, &val) < 0)
426 be->num_regs = atoi(val);
427 tplg_dbg("\t%s: %d\n", id, be->num_regs);
431 if (strcmp(id, "max") == 0) {
432 if (snd_config_get_string(n, &val) < 0)
436 tplg_dbg("\t%s: %d\n", id, be->max);
440 if (strcmp(id, "mask") == 0) {
441 if (snd_config_get_string(n, &val) < 0)
444 be->mask = strtol(val, NULL, 16);
445 tplg_dbg("\t%s: %d\n", id, be->mask);
449 if (strcmp(id, "data") == 0) {
450 if (snd_config_get_string(n, &val) < 0)
453 tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
454 tplg_dbg("\t%s: %s\n", id, val);
458 if (strcmp(id, "tlv") == 0) {
459 if (snd_config_get_string(n, &val) < 0)
462 err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
467 tplg_dbg("\t%s: %s\n", id, val);
471 if (strcmp(id, "ops") == 0) {
472 err = tplg_parse_compound(tplg, n, tplg_parse_ops,
479 if (strcmp(id, "extops") == 0) {
480 err = tplg_parse_compound(tplg, n, tplg_parse_ext_ops,
487 if (strcmp(id, "access") == 0) {
488 err = parse_access(cfg, &be->hdr);
496 /* set CTL access to default values if none are provided */
499 be->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
501 be->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
507 /* Parse Control Enums. */
508 int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
509 void *private ATTRIBUTE_UNUSED)
511 struct snd_soc_tplg_enum_control *ec;
512 struct tplg_elem *elem;
513 snd_config_iterator_t i, next;
515 const char *id, *val = NULL;
517 bool access_set = false;
519 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM);
523 ec = elem->enum_ctrl;
524 elem_copy_text(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
525 ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM;
526 ec->size = elem->size;
527 tplg->channel_idx = 0;
529 /* set channel reg to default state */
530 for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
531 ec->channel[j].reg = -1;
533 tplg_dbg(" Control Enum: %s\n", elem->id);
535 snd_config_for_each(i, next, cfg) {
537 n = snd_config_iterator_entry(i);
538 if (snd_config_get_id(n, &id) < 0)
542 if (strcmp(id, "comment") == 0)
547 if (strcmp(id, "index") == 0) {
548 if (snd_config_get_string(n, &val) < 0)
551 elem->index = atoi(val);
552 tplg_dbg("\t%s: %d\n", id, elem->index);
556 if (strcmp(id, "texts") == 0) {
557 if (snd_config_get_string(n, &val) < 0)
560 tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val);
561 tplg_dbg("\t%s: %s\n", id, val);
565 if (strcmp(id, "channel") == 0) {
566 if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
567 SNDERR("error: too many channels %s\n",
572 err = tplg_parse_compound(tplg, n, tplg_parse_channel,
577 ec->num_channels = tplg->channel_idx;
581 if (strcmp(id, "ops") == 0) {
582 err = tplg_parse_compound(tplg, n, tplg_parse_ops,
589 if (strcmp(id, "data") == 0) {
590 if (snd_config_get_string(n, &val) < 0)
593 tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
594 tplg_dbg("\t%s: %s\n", id, val);
598 if (strcmp(id, "access") == 0) {
599 err = parse_access(cfg, &ec->hdr);
607 /* set CTL access to default values if none are provided */
609 ec->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
617 * Mixer control. Supports multiple channels.
619 int tplg_parse_control_mixer(snd_tplg_t *tplg,
620 snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
622 struct snd_soc_tplg_mixer_control *mc;
623 struct tplg_elem *elem;
624 snd_config_iterator_t i, next;
626 const char *id, *val = NULL;
628 bool access_set = false, tlv_set = false;
630 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MIXER);
635 mc = elem->mixer_ctrl;
636 elem_copy_text(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
637 mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER;
638 mc->size = elem->size;
639 tplg->channel_idx = 0;
641 /* set channel reg to default state */
642 for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
643 mc->channel[j].reg = -1;
645 tplg_dbg(" Control Mixer: %s\n", elem->id);
647 /* giterate trough each mixer elment */
648 snd_config_for_each(i, next, cfg) {
649 n = snd_config_iterator_entry(i);
650 if (snd_config_get_id(n, &id) < 0)
654 if (strcmp(id, "comment") == 0)
659 if (strcmp(id, "index") == 0) {
660 if (snd_config_get_string(n, &val) < 0)
663 elem->index = atoi(val);
664 tplg_dbg("\t%s: %d\n", id, elem->index);
668 if (strcmp(id, "channel") == 0) {
669 if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
670 SNDERR("error: too many channels %s\n",
675 err = tplg_parse_compound(tplg, n, tplg_parse_channel,
680 mc->num_channels = tplg->channel_idx;
684 if (strcmp(id, "max") == 0) {
685 if (snd_config_get_string(n, &val) < 0)
689 tplg_dbg("\t%s: %d\n", id, mc->max);
693 if (strcmp(id, "invert") == 0) {
694 if (snd_config_get_string(n, &val) < 0)
697 if (strcmp(val, "true") == 0)
699 else if (strcmp(val, "false") == 0)
702 tplg_dbg("\t%s: %d\n", id, mc->invert);
706 if (strcmp(id, "ops") == 0) {
707 err = tplg_parse_compound(tplg, n, tplg_parse_ops,
714 if (strcmp(id, "tlv") == 0) {
715 if (snd_config_get_string(n, &val) < 0)
718 err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
723 tplg_dbg("\t%s: %s\n", id, val);
727 if (strcmp(id, "data") == 0) {
728 if (snd_config_get_string(n, &val) < 0)
731 tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
732 tplg_dbg("\t%s: %s\n", id, val);
736 if (strcmp(id, "access") == 0) {
737 err = parse_access(cfg, &mc->hdr);
745 /* set CTL access to default values if none are provided */
748 mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
750 mc->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
756 static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
757 struct snd_tplg_ctl_template *t)
759 hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr);
762 elem_copy_text(hdr->name, t->name,
763 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
765 /* clean up access flag */
767 t->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
768 t->access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
769 SNDRV_CTL_ELEM_ACCESS_VOLATILE |
770 SNDRV_CTL_ELEM_ACCESS_INACTIVE |
771 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
772 SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
773 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
775 hdr->access = t->access;
776 hdr->ops.get = t->ops.get;
777 hdr->ops.put = t->ops.put;
778 hdr->ops.info = t->ops.info;
781 if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
782 && !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
784 struct snd_tplg_tlv_template *tlvt = t->tlv;
785 struct snd_soc_tplg_ctl_tlv *tlv = &hdr->tlv;
786 struct snd_tplg_tlv_dbscale_template *scalet;
787 struct snd_soc_tplg_tlv_dbscale *scale;
790 SNDERR("error: missing TLV data\n");
794 tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
795 tlv->type = tlvt->type;
797 switch (tlvt->type) {
798 case SNDRV_CTL_TLVT_DB_SCALE:
799 scalet = container_of(tlvt,
800 struct snd_tplg_tlv_dbscale_template, hdr);
802 scale->min = scalet->min;
803 scale->step = scalet->step;
804 scale->mute = scalet->mute;
807 /* TODO: add support for other TLV types */
809 SNDERR("error: unsupported TLV type %d\n", tlv->type);
817 int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
818 struct tplg_elem **e)
820 struct snd_soc_tplg_private *priv = mixer->priv;
821 struct snd_soc_tplg_mixer_control *mc;
822 struct tplg_elem *elem;
823 int ret, i, num_channels;
825 tplg_dbg(" Control Mixer: %s\n", mixer->hdr.name);
827 if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) {
828 SNDERR("error: invalid mixer type %d\n", mixer->hdr.type);
832 elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name,
833 SND_TPLG_TYPE_MIXER);
838 mc = elem->mixer_ctrl;
839 mc->size = elem->size;
840 ret = init_ctl_hdr(&mc->hdr, &mixer->hdr);
842 tplg_elem_free(elem);
846 mc->min = mixer->min;
847 mc->max = mixer->max;
848 mc->platform_max = mixer->platform_max;
849 mc->invert = mixer->invert;
851 /* set channel reg to default state */
852 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
853 mc->channel[i].reg = -1;
855 num_channels = mixer->map ? mixer->map->num_channels : 0;
856 mc->num_channels = num_channels;
858 for (i = 0; i < num_channels; i++) {
859 struct snd_tplg_channel_elem *channel = &mixer->map->channel[i];
861 mc->channel[i].size = channel->size;
862 mc->channel[i].reg = channel->reg;
863 mc->channel[i].shift = channel->shift;
864 mc->channel[i].id = channel->id;
869 mc = realloc(mc, elem->size + priv->size);
871 tplg_elem_free(elem);
875 elem->mixer_ctrl = mc;
876 elem->size += priv->size;
877 mc->priv.size = priv->size;
878 memcpy(mc->priv.data, priv->data, priv->size);
886 int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
887 struct tplg_elem **e)
889 struct snd_soc_tplg_enum_control *ec;
890 struct tplg_elem *elem;
891 int ret, i, num_items;
893 tplg_dbg(" Control Enum: %s\n", enum_ctl->hdr.name);
895 if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) {
896 SNDERR("error: invalid enum type %d\n", enum_ctl->hdr.type);
900 elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name,
905 ec = elem->enum_ctrl;
906 ec->size = elem->size;
907 ret = init_ctl_hdr(&ec->hdr, &enum_ctl->hdr);
909 tplg_elem_free(elem);
913 num_items = enum_ctl->items < SND_SOC_TPLG_NUM_TEXTS ?
914 enum_ctl->items : SND_SOC_TPLG_NUM_TEXTS;
915 ec->items = num_items;
916 ec->mask = enum_ctl->mask;
917 ec->count = enum_ctl->items;
919 if (enum_ctl->texts != NULL) {
920 for (i = 0; i < num_items; i++) {
921 if (enum_ctl->texts[i] != NULL)
922 strncpy(ec->texts[i], enum_ctl->texts[i],
923 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
927 if (enum_ctl->values != NULL) {
928 for (i = 0; i < num_items; i++) {
929 if (enum_ctl->values[i])
932 memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE],
934 sizeof(int) * ENUM_VAL_SIZE);
938 if (enum_ctl->priv != NULL) {
940 elem->size + enum_ctl->priv->size);
942 tplg_elem_free(elem);
946 elem->enum_ctrl = ec;
947 elem->size += enum_ctl->priv->size;
949 memcpy(ec->priv.data, enum_ctl->priv->data,
950 enum_ctl->priv->size);
952 ec->priv.size = enum_ctl->priv->size;
960 int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
961 struct tplg_elem **e)
963 struct snd_soc_tplg_bytes_control *be;
964 struct tplg_elem *elem;
967 tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name);
969 if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
970 SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type);
974 elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
975 SND_TPLG_TYPE_BYTES);
979 be = elem->bytes_ext;
980 be->size = elem->size;
981 ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr);
983 tplg_elem_free(elem);
987 be->max = bytes_ctl->max;
988 be->mask = bytes_ctl->mask;
989 be->base = bytes_ctl->base;
990 be->num_regs = bytes_ctl->num_regs;
991 be->ext_ops.put = bytes_ctl->ext_ops.put;
992 be->ext_ops.get = bytes_ctl->ext_ops.get;
994 if (bytes_ctl->priv != NULL) {
996 elem->size + bytes_ctl->priv->size);
998 tplg_elem_free(elem);
1001 elem->bytes_ext = be;
1002 elem->size += bytes_ctl->priv->size;
1004 memcpy(be->priv.data, bytes_ctl->priv->data,
1005 bytes_ctl->priv->size);
1007 be->priv.size = bytes_ctl->priv->size;
1010 /* check on TLV bytes control */
1011 if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1012 if ((be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
1013 != SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
1014 SNDERR("error: Invalid TLV bytes control access 0x%x\n",
1016 tplg_elem_free(elem);
1021 tplg_elem_free(elem);
1031 int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1033 return tplg_add_mixer(tplg, t->mixer, NULL);
1036 int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1038 return tplg_add_enum(tplg, t->enum_ctl, NULL);
1041 int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1043 return tplg_add_bytes(tplg, t->bytes_ctl, NULL);