OSDN Git Service

23c196a35764d59ced9b3aae0d9ee2ab5eb23fb9
[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 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.
8
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.
13
14   Authors: Mengdong Lin <mengdong.lin@intel.com>
15            Yao Jin <yao.jin@intel.com>
16            Liam Girdwood <liam.r.girdwood@linux.intel.com>
17 */
18
19 #include "list.h"
20 #include "tplg_local.h"
21
22 #define ENUM_VAL_SIZE   (SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2)
23
24 /* copy referenced TLV to the mixer control */
25 static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
26 {
27         struct snd_soc_tplg_mixer_control *mixer_ctrl =  elem->mixer_ctrl;
28         struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
29
30         tplg_dbg("TLV '%s' used by '%s\n", ref->id, elem->id);
31
32         /* TLV has a fixed size */
33         mixer_ctrl->hdr.tlv = *tlv;
34         return 0;
35 }
36
37 /* check referenced TLV for a mixer control */
38 static int tplg_build_mixer_control(snd_tplg_t *tplg,
39                                 struct tplg_elem *elem)
40 {
41         struct tplg_ref *ref;
42         struct list_head *base, *pos;
43         int err = 0;
44
45         base = &elem->ref_list;
46
47         /* for each ref in this control elem */
48         list_for_each(pos, base) {
49
50                 ref = list_entry(pos, struct tplg_ref, list);
51                 if (ref->id == NULL || ref->elem)
52                         continue;
53
54                 if (ref->type == SND_TPLG_TYPE_TLV) {
55                         ref->elem = tplg_elem_lookup(&tplg->tlv_list,
56                                                 ref->id, SND_TPLG_TYPE_TLV);
57                         if (ref->elem)
58                                  err = copy_tlv(elem, ref->elem);
59
60                 } else if (ref->type == SND_TPLG_TYPE_DATA) {
61                         ref->elem = tplg_elem_lookup(&tplg->pdata_list,
62                                                 ref->id, SND_TPLG_TYPE_DATA);
63                          err = tplg_copy_data(elem, ref->elem);
64                 }
65
66                 if (!ref->elem) {
67                         SNDERR("error: cannot find '%s' referenced by"
68                                 " control '%s'\n", ref->id, elem->id);
69                         return -EINVAL;
70                 } else if (err < 0)
71                         return err;
72         }
73
74         return 0;
75 }
76
77 static void copy_enum_texts(struct tplg_elem *enum_elem,
78         struct tplg_elem *ref_elem)
79 {
80         struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
81
82         memcpy(ec->texts, ref_elem->texts,
83                 SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
84 }
85
86 /* check referenced text for a enum control */
87 static int tplg_build_enum_control(snd_tplg_t *tplg,
88                                 struct tplg_elem *elem)
89 {
90         struct tplg_ref *ref;
91         struct list_head *base, *pos;
92         int err = 0;
93
94         base = &elem->ref_list;
95
96         list_for_each(pos, base) {
97
98                 ref = list_entry(pos, struct tplg_ref, list);
99                 if (ref->id == NULL || ref->elem)
100                         continue;
101
102                 if (ref->type == SND_TPLG_TYPE_TEXT) {
103                         ref->elem = tplg_elem_lookup(&tplg->text_list,
104                                                 ref->id, SND_TPLG_TYPE_TEXT);
105                         if (ref->elem)
106                                 copy_enum_texts(elem, ref->elem);
107
108                 } else if (ref->type == SND_TPLG_TYPE_DATA) {
109                         ref->elem = tplg_elem_lookup(&tplg->pdata_list,
110                                                 ref->id, SND_TPLG_TYPE_DATA);
111                         err = tplg_copy_data(elem, ref->elem);
112                 }
113                 if (!ref->elem) {
114                         SNDERR("error: cannot find '%s' referenced by"
115                                 " control '%s'\n", ref->id, elem->id);
116                         return -EINVAL;
117                 } else if (err < 0)
118                         return err;
119         }
120
121         return 0;
122 }
123
124 /* check referenced private data for a byte control */
125 static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
126 {
127         struct tplg_ref *ref;
128         struct list_head *base, *pos;
129
130         base = &elem->ref_list;
131
132         list_for_each(pos, base) {
133
134                 ref = list_entry(pos, struct tplg_ref, list);
135                 if (ref->id == NULL || ref->elem)
136                         continue;
137
138                 /* bytes control only reference one private data section */
139                 ref->elem = tplg_elem_lookup(&tplg->pdata_list,
140                         ref->id, SND_TPLG_TYPE_DATA);
141                 if (!ref->elem) {
142                         SNDERR("error: cannot find data '%s'"
143                                 " referenced by control '%s'\n",
144                                 ref->id, elem->id);
145                         return -EINVAL;
146                 }
147
148                 /* copy texts to enum elem */
149                 return tplg_copy_data(elem, ref->elem);
150         }
151
152         return 0;
153 }
154
155 int tplg_build_controls(snd_tplg_t *tplg)
156 {
157         struct list_head *base, *pos;
158         struct tplg_elem *elem;
159         int err = 0;
160
161         base = &tplg->mixer_list;
162         list_for_each(pos, base) {
163
164                 elem = list_entry(pos, struct tplg_elem, list);
165                 err = tplg_build_mixer_control(tplg, elem);
166                 if (err < 0)
167                         return err;
168
169                 /* add control to manifest */
170                 tplg->manifest.control_elems++;
171         }
172
173         base = &tplg->enum_list;
174         list_for_each(pos, base) {
175
176                 elem = list_entry(pos, struct tplg_elem, list);
177                 err = tplg_build_enum_control(tplg, elem);
178                 if (err < 0)
179                         return err;
180
181                 /* add control to manifest */
182                 tplg->manifest.control_elems++;
183         }
184
185         base = &tplg->bytes_ext_list;
186         list_for_each(pos, base) {
187
188                 elem = list_entry(pos, struct tplg_elem, list);
189                 err = tplg_build_bytes_control(tplg, elem);
190                 if (err < 0)
191                         return err;
192
193                 /* add control to manifest */
194                 tplg->manifest.control_elems++;
195         }
196
197         return 0;
198 }
199
200
201 /*
202  * Parse TLV of DBScale type.
203  *
204  * Parse DBScale describing min, step, mute in DB.
205  */
206 static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem)
207 {
208         snd_config_iterator_t i, next;
209         snd_config_t *n;
210         struct snd_soc_tplg_ctl_tlv *tplg_tlv;
211         struct snd_soc_tplg_tlv_dbscale *scale;
212         const char *id = NULL, *value = NULL;
213
214         tplg_dbg(" scale: %s\n", elem->id);
215
216         tplg_tlv = calloc(1, sizeof(*tplg_tlv));
217         if (!tplg_tlv)
218                 return -ENOMEM;
219
220         elem->tlv = tplg_tlv;
221         tplg_tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
222         tplg_tlv->type = SNDRV_CTL_TLVT_DB_SCALE;
223         scale = &tplg_tlv->scale;
224
225         snd_config_for_each(i, next, cfg) {
226
227                 n = snd_config_iterator_entry(i);
228
229                 /* get ID */
230                 if (snd_config_get_id(n, &id) < 0) {
231                         SNDERR("error: cant get ID\n");
232                         return -EINVAL;
233                 }
234
235                 /* get value */
236                 if (snd_config_get_string(n, &value) < 0)
237                         continue;
238
239                 tplg_dbg("\t%s = %s\n", id, value);
240
241                 /* get TLV data */
242                 if (strcmp(id, "min") == 0)
243                         scale->min = atoi(value);
244                 else if (strcmp(id, "step") == 0)
245                         scale->step = atoi(value);
246                 else if (strcmp(id, "mute") == 0)
247                         scale->mute = atoi(value);
248                 else
249                         SNDERR("error: unknown key %s\n", id);
250         }
251
252         return 0;
253 }
254
255 /* Parse TLV */
256 int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
257         void *private ATTRIBUTE_UNUSED)
258 {
259         snd_config_iterator_t i, next;
260         snd_config_t *n;
261         const char *id;
262         int err = 0;
263         struct tplg_elem *elem;
264
265         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV);
266         if (!elem)
267                 return -ENOMEM;
268
269         snd_config_for_each(i, next, cfg) {
270
271                 n = snd_config_iterator_entry(i);
272                 if (snd_config_get_id(n, &id) < 0)
273                         continue;
274
275                 if (strcmp(id, "scale") == 0) {
276                         err = tplg_parse_tlv_dbscale(n, elem);
277                         if (err < 0) {
278                                 SNDERR("error: failed to DBScale");
279                                 return err;
280                         }
281                         continue;
282                 }
283         }
284
285         return err;
286 }
287
288 /* Parse Control Bytes */
289 int tplg_parse_control_bytes(snd_tplg_t *tplg,
290         snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
291 {
292         struct snd_soc_tplg_bytes_control *be;
293         struct tplg_elem *elem;
294         snd_config_iterator_t i, next;
295         snd_config_t *n;
296         const char *id, *val = NULL;
297         int err;
298
299         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES);
300         if (!elem)
301                 return -ENOMEM;
302
303         be = elem->bytes_ext;
304         be->size = elem->size;
305         elem_copy_text(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
306         be->hdr.type = SND_SOC_TPLG_TYPE_BYTES;
307
308         tplg_dbg(" Control Bytes: %s\n", elem->id);
309
310         snd_config_for_each(i, next, cfg) {
311                 n = snd_config_iterator_entry(i);
312                 if (snd_config_get_id(n, &id) < 0)
313                         continue;
314
315                 /* skip comments */
316                 if (strcmp(id, "comment") == 0)
317                         continue;
318                 if (id[0] == '#')
319                         continue;
320
321                 if (strcmp(id, "index") == 0) {
322                         if (snd_config_get_string(n, &val) < 0)
323                                 return -EINVAL;
324
325                         elem->index = atoi(val);
326                         tplg_dbg("\t%s: %d\n", id, elem->index);
327                         continue;
328                 }
329
330                 if (strcmp(id, "base") == 0) {
331                         if (snd_config_get_string(n, &val) < 0)
332                                 return -EINVAL;
333
334                         be->base = atoi(val);
335                         tplg_dbg("\t%s: %d\n", id, be->base);
336                         continue;
337                 }
338
339                 if (strcmp(id, "num_regs") == 0) {
340                         if (snd_config_get_string(n, &val) < 0)
341                                 return -EINVAL;
342
343                         be->num_regs = atoi(val);
344                         tplg_dbg("\t%s: %d\n", id, be->num_regs);
345                         continue;
346                 }
347
348                 if (strcmp(id, "max") == 0) {
349                         if (snd_config_get_string(n, &val) < 0)
350                                 return -EINVAL;
351
352                         be->max = atoi(val);
353                         tplg_dbg("\t%s: %d\n", id, be->max);
354                         continue;
355                 }
356
357                 if (strcmp(id, "mask") == 0) {
358                         if (snd_config_get_string(n, &val) < 0)
359                                 return -EINVAL;
360
361                         be->mask = strtol(val, NULL, 16);
362                         tplg_dbg("\t%s: %d\n", id, be->mask);
363                         continue;
364                 }
365
366                 if (strcmp(id, "data") == 0) {
367                         if (snd_config_get_string(n, &val) < 0)
368                                 return -EINVAL;
369
370                         tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
371                         tplg_dbg("\t%s: %s\n", id, val);
372                         continue;
373                 }
374
375                 if (strcmp(id, "tlv") == 0) {
376                         if (snd_config_get_string(n, &val) < 0)
377                                 return -EINVAL;
378
379                         err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
380                         if (err < 0)
381                                 return err;
382
383                         be->hdr.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
384                                 SNDRV_CTL_ELEM_ACCESS_READWRITE;
385                         tplg_dbg("\t%s: %s\n", id, val);
386                         continue;
387                 }
388
389                 if (strcmp(id, "ops") == 0) {
390                         err = tplg_parse_compound(tplg, n, tplg_parse_ops,
391                                 &be->hdr);
392                         if (err < 0)
393                                 return err;
394                         continue;
395                 }
396
397                 if (strcmp(id, "extops") == 0) {
398                         err = tplg_parse_compound(tplg, n, tplg_parse_ext_ops,
399                                 be);
400                         if (err < 0)
401                                 return err;
402                         continue;
403                 }
404         }
405
406         return 0;
407 }
408
409 /* Parse Control Enums. */
410 int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
411         void *private ATTRIBUTE_UNUSED)
412 {
413         struct snd_soc_tplg_enum_control *ec;
414         struct tplg_elem *elem;
415         snd_config_iterator_t i, next;
416         snd_config_t *n;
417         const char *id, *val = NULL;
418         int err, j;
419
420         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM);
421         if (!elem)
422                 return -ENOMEM;
423
424         ec = elem->enum_ctrl;
425         elem_copy_text(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
426         ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM;
427         ec->size = elem->size;
428         tplg->channel_idx = 0;
429
430         /* set channel reg to default state */
431         for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
432                 ec->channel[j].reg = -1;
433
434         tplg_dbg(" Control Enum: %s\n", elem->id);
435
436         snd_config_for_each(i, next, cfg) {
437
438                 n = snd_config_iterator_entry(i);
439                 if (snd_config_get_id(n, &id) < 0)
440                         continue;
441
442                 /* skip comments */
443                 if (strcmp(id, "comment") == 0)
444                         continue;
445                 if (id[0] == '#')
446                         continue;
447
448                 if (strcmp(id, "index") == 0) {
449                         if (snd_config_get_string(n, &val) < 0)
450                                 return -EINVAL;
451
452                         elem->index = atoi(val);
453                         tplg_dbg("\t%s: %d\n", id, elem->index);
454                         continue;
455                 }
456
457                 if (strcmp(id, "texts") == 0) {
458                         if (snd_config_get_string(n, &val) < 0)
459                                 return -EINVAL;
460
461                         tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val);
462                         tplg_dbg("\t%s: %s\n", id, val);
463                         continue;
464                 }
465
466                 if (strcmp(id, "channel") == 0) {
467                         if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
468                                 SNDERR("error: too many channels %s\n",
469                                         elem->id);
470                                 return -EINVAL;
471                         }
472
473                         err = tplg_parse_compound(tplg, n, tplg_parse_channel,
474                                 ec->channel);
475                         if (err < 0)
476                                 return err;
477
478                         ec->num_channels = tplg->channel_idx;
479                         continue;
480                 }
481
482                 if (strcmp(id, "ops") == 0) {
483                         err = tplg_parse_compound(tplg, n, tplg_parse_ops,
484                                 &ec->hdr);
485                         if (err < 0)
486                                 return err;
487                         continue;
488                 }
489
490                 if (strcmp(id, "data") == 0) {
491                         if (snd_config_get_string(n, &val) < 0)
492                                 return -EINVAL;
493
494                         tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
495                         tplg_dbg("\t%s: %s\n", id, val);
496                         continue;
497                 }
498         }
499
500         return 0;
501 }
502
503 /* Parse Controls.
504  *
505  * Mixer control. Supports multiple channels.
506  */
507 int tplg_parse_control_mixer(snd_tplg_t *tplg,
508         snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
509 {
510         struct snd_soc_tplg_mixer_control *mc;
511         struct tplg_elem *elem;
512         snd_config_iterator_t i, next;
513         snd_config_t *n;
514         const char *id, *val = NULL;
515         int err, j;
516
517         elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MIXER);
518         if (!elem)
519                 return -ENOMEM;
520
521         /* init new mixer */
522         mc = elem->mixer_ctrl;
523         elem_copy_text(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
524         mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER;
525         mc->size = elem->size;
526         tplg->channel_idx = 0;
527
528         /* set channel reg to default state */
529         for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
530                 mc->channel[j].reg = -1;
531
532         tplg_dbg(" Control Mixer: %s\n", elem->id);
533
534         /* giterate trough each mixer elment */
535         snd_config_for_each(i, next, cfg) {
536                 n = snd_config_iterator_entry(i);
537                 if (snd_config_get_id(n, &id) < 0)
538                         continue;
539
540                 /* skip comments */
541                 if (strcmp(id, "comment") == 0)
542                         continue;
543                 if (id[0] == '#')
544                         continue;
545
546                 if (strcmp(id, "index") == 0) {
547                         if (snd_config_get_string(n, &val) < 0)
548                                 return -EINVAL;
549
550                         elem->index = atoi(val);
551                         tplg_dbg("\t%s: %d\n", id, elem->index);
552                         continue;
553                 }
554
555                 if (strcmp(id, "channel") == 0) {
556                         if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
557                                 SNDERR("error: too many channels %s\n",
558                                         elem->id);
559                                 return -EINVAL;
560                         }
561
562                         err = tplg_parse_compound(tplg, n, tplg_parse_channel,
563                                 mc->channel);
564                         if (err < 0)
565                                 return err;
566
567                         mc->num_channels = tplg->channel_idx;
568                         continue;
569                 }
570
571                 if (strcmp(id, "max") == 0) {
572                         if (snd_config_get_string(n, &val) < 0)
573                                 return -EINVAL;
574
575                         mc->max = atoi(val);
576                         tplg_dbg("\t%s: %d\n", id, mc->max);
577                         continue;
578                 }
579
580                 if (strcmp(id, "invert") == 0) {
581                         if (snd_config_get_string(n, &val) < 0)
582                                 return -EINVAL;
583
584                         if (strcmp(val, "true") == 0)
585                                 mc->invert = 1;
586                         else if (strcmp(val, "false") == 0)
587                                 mc->invert = 0;
588
589                         tplg_dbg("\t%s: %d\n", id, mc->invert);
590                         continue;
591                 }
592
593                 if (strcmp(id, "ops") == 0) {
594                         err = tplg_parse_compound(tplg, n, tplg_parse_ops,
595                                 &mc->hdr);
596                         if (err < 0)
597                                 return err;
598                         continue;
599                 }
600
601                 if (strcmp(id, "tlv") == 0) {
602                         if (snd_config_get_string(n, &val) < 0)
603                                 return -EINVAL;
604
605                         err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
606                         if (err < 0)
607                                 return err;
608
609                         mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
610                                 SNDRV_CTL_ELEM_ACCESS_READWRITE;
611                         tplg_dbg("\t%s: %s\n", id, val);
612                         continue;
613                 }
614
615                 if (strcmp(id, "data") == 0) {
616                         if (snd_config_get_string(n, &val) < 0)
617                                 return -EINVAL;
618
619                         tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
620                         tplg_dbg("\t%s: %s\n", id, val);
621                         continue;
622                 }
623         }
624
625         return 0;
626 }
627
628 static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
629                 struct snd_tplg_ctl_template *t)
630 {
631         hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr);
632         hdr->type = t->type;
633
634         elem_copy_text(hdr->name, t->name,
635                 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
636
637         /* clean up access flag */
638         if (t->access == 0)
639                 t->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
640         t->access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
641                 SNDRV_CTL_ELEM_ACCESS_VOLATILE |
642                 SNDRV_CTL_ELEM_ACCESS_INACTIVE |
643                 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
644                 SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
645                 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
646
647         hdr->access = t->access;
648         hdr->ops.get = t->ops.get;
649         hdr->ops.put = t->ops.put;
650         hdr->ops.info = t->ops.info;
651
652         /* TLV */
653         if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
654                 && !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
655
656                 struct snd_tplg_tlv_template *tlvt = t->tlv;
657                 struct snd_soc_tplg_ctl_tlv *tlv = &hdr->tlv;
658                 struct snd_tplg_tlv_dbscale_template *scalet;
659                 struct snd_soc_tplg_tlv_dbscale *scale;
660
661                 if (!tlvt) {
662                         SNDERR("error: missing TLV data\n");
663                         return -EINVAL;
664                 }
665
666                 tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
667                 tlv->type = tlvt->type;
668
669                 switch (tlvt->type) {
670                 case SNDRV_CTL_TLVT_DB_SCALE:
671                         scalet = container_of(tlvt,
672                                 struct snd_tplg_tlv_dbscale_template, hdr);
673                         scale = &tlv->scale;
674                         scale->min = scalet->min;
675                         scale->step = scalet->step;
676                         scale->mute = scalet->mute;
677                         break;
678
679                 /* TODO: add support for other TLV types */
680                 default:
681                         SNDERR("error: unsupported TLV type %d\n", tlv->type);
682                         break;
683                 }
684         }
685
686         return 0;
687 }
688
689 int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
690         struct tplg_elem **e)
691 {
692         struct snd_soc_tplg_private *priv = mixer->priv;
693         struct snd_soc_tplg_mixer_control *mc;
694         struct tplg_elem *elem;
695         int ret, i, num_channels;
696
697         tplg_dbg(" Control Mixer: %s\n", mixer->hdr.name);
698
699         if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) {
700                 SNDERR("error: invalid mixer type %d\n", mixer->hdr.type);
701                 return -EINVAL;
702         }
703
704         elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name,
705                 SND_TPLG_TYPE_MIXER);
706         if (!elem)
707                 return -ENOMEM;
708
709         /* init new mixer */
710         mc = elem->mixer_ctrl;
711         mc->size = elem->size;
712         ret =  init_ctl_hdr(&mc->hdr, &mixer->hdr);
713         if (ret < 0) {
714                 tplg_elem_free(elem);
715                 return ret;
716         }
717
718         mc->min = mixer->min;
719         mc->max = mixer->max;
720         mc->platform_max = mixer->platform_max;
721         mc->invert = mixer->invert;
722
723         /* set channel reg to default state */
724         for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
725                 mc->channel[i].reg = -1;
726
727         num_channels = mixer->map ? mixer->map->num_channels : 0;
728         mc->num_channels = num_channels;
729
730         for (i = 0; i < num_channels; i++) {
731                 struct snd_tplg_channel_elem *channel = &mixer->map->channel[i];
732
733                 mc->channel[i].size = channel->size;
734                 mc->channel[i].reg = channel->reg;
735                 mc->channel[i].shift = channel->shift;
736                 mc->channel[i].id = channel->id;
737         }
738
739         /* priv data */
740         if (priv) {
741                 mc = realloc(mc, elem->size + priv->size);
742                 if (!mc) {
743                         tplg_elem_free(elem);
744                         return -ENOMEM;
745                 }
746
747                 elem->mixer_ctrl = mc;
748                 elem->size += priv->size;
749                 mc->priv.size = priv->size;
750                 memcpy(mc->priv.data, priv->data,  priv->size);
751         }
752
753         if (e)
754                 *e = elem;
755         return 0;
756 }
757
758 int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
759         struct tplg_elem **e)
760 {
761         struct snd_soc_tplg_enum_control *ec;
762         struct tplg_elem *elem;
763         int ret, i, num_items;
764
765         tplg_dbg(" Control Enum: %s\n", enum_ctl->hdr.name);
766
767         if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) {
768                 SNDERR("error: invalid enum type %d\n", enum_ctl->hdr.type);
769                 return -EINVAL;
770         }
771
772         elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name,
773                 SND_TPLG_TYPE_ENUM);
774         if (!elem)
775                 return -ENOMEM;
776
777         ec = elem->enum_ctrl;
778         ec->size = elem->size;
779         ret = init_ctl_hdr(&ec->hdr, &enum_ctl->hdr);
780         if (ret < 0) {
781                 tplg_elem_free(elem);
782                 return ret;
783         }
784
785         num_items =  enum_ctl->items < SND_SOC_TPLG_NUM_TEXTS ?
786                 enum_ctl->items : SND_SOC_TPLG_NUM_TEXTS;
787         ec->items = num_items;
788         ec->mask = enum_ctl->mask;
789         ec->count = enum_ctl->items;
790
791         if (enum_ctl->texts != NULL) {
792                 for (i = 0; i < num_items; i++) {
793                         if (enum_ctl->texts[i] != NULL)
794                                 strncpy(ec->texts[i], enum_ctl->texts[i],
795                                         SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
796                 }
797         }
798
799         if (enum_ctl->values != NULL) {
800                 for (i = 0; i < num_items; i++) {
801                         if (enum_ctl->values[i])
802                                 continue;
803
804                         memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE],
805                                 enum_ctl->values[i],
806                                 sizeof(int) * ENUM_VAL_SIZE);
807                 }
808         }
809
810         if (enum_ctl->priv != NULL) {
811                 ec = realloc(ec,
812                         elem->size + enum_ctl->priv->size);
813                 if (!ec) {
814                         tplg_elem_free(elem);
815                         return -ENOMEM;
816                 }
817
818                 elem->enum_ctrl = ec;
819                 elem->size += enum_ctl->priv->size;
820
821                 memcpy(ec->priv.data, enum_ctl->priv->data,
822                         enum_ctl->priv->size);
823
824                 ec->priv.size = enum_ctl->priv->size;
825         }
826
827         if (e)
828                 *e = elem;
829         return 0;
830 }
831
832 int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
833         struct tplg_elem **e)
834 {
835         struct snd_soc_tplg_bytes_control *be;
836         struct tplg_elem *elem;
837         int ret;
838
839         tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name);
840
841         if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
842                 SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type);
843                 return -EINVAL;
844         }
845
846         elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
847                 SND_TPLG_TYPE_BYTES);
848         if (!elem)
849                 return -ENOMEM;
850
851         be = elem->bytes_ext;
852         be->size = elem->size;
853         ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr);
854         if (ret < 0) {
855                 tplg_elem_free(elem);
856                 return ret;
857         }
858
859         be->max = bytes_ctl->max;
860         be->mask = bytes_ctl->mask;
861         be->base = bytes_ctl->base;
862         be->num_regs = bytes_ctl->num_regs;
863         be->ext_ops.put = bytes_ctl->ext_ops.put;
864         be->ext_ops.get = bytes_ctl->ext_ops.get;
865
866         if (bytes_ctl->priv != NULL) {
867                 be = realloc(be,
868                         elem->size + bytes_ctl->priv->size);
869                 if (!be) {
870                         tplg_elem_free(elem);
871                         return -ENOMEM;
872                 }
873                 elem->bytes_ext = be;
874                 elem->size += bytes_ctl->priv->size;
875
876                 memcpy(be->priv.data, bytes_ctl->priv->data,
877                         bytes_ctl->priv->size);
878
879                 be->priv.size = bytes_ctl->priv->size;
880         }
881
882         /* check on TLV bytes control */
883         if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
884                 if ((be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
885                         != SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
886                         SNDERR("error: Invalid TLV bytes control access 0x%x\n",
887                                 be->hdr.access);
888                         tplg_elem_free(elem);
889                         return -EINVAL;
890                 }
891
892                 if (!be->max) {
893                         tplg_elem_free(elem);
894                         return -EINVAL;
895                 }
896         }
897
898         if (e)
899                 *e = elem;
900         return 0;
901 }
902
903 int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
904 {
905         return tplg_add_mixer(tplg, t->mixer, NULL);
906 }
907
908 int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
909 {
910         return tplg_add_enum(tplg, t->enum_ctl, NULL);
911 }
912
913 int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
914 {
915         return tplg_add_bytes(tplg, t->bytes_ctl, NULL);
916 }