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 */
parse_access_values(snd_config_t * cfg,struct snd_soc_tplg_ctl_hdr * hdr)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 */
parse_access(snd_config_t * cfg,struct snd_soc_tplg_ctl_hdr * hdr)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 */
tplg_save_access(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct snd_soc_tplg_ctl_hdr * hdr,struct tplg_buf * dst,const char * pfx)107 static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
108 struct snd_soc_tplg_ctl_hdr *hdr,
109 struct tplg_buf *dst, 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 */
copy_tlv(struct tplg_elem * elem,struct tplg_elem * ref)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 */
tplg_build_mixer_control(snd_tplg_t * tplg,struct tplg_elem * elem)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
copy_enum_texts(struct tplg_elem * enum_elem,struct tplg_elem * ref_elem)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 */
tplg_build_enum_control(snd_tplg_t * tplg,struct tplg_elem * elem)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 */
tplg_build_bytes_control(snd_tplg_t * tplg,struct tplg_elem * elem)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
tplg_build_controls(snd_tplg_t * tplg)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 */
tplg_parse_tlv_dbscale(snd_config_t * cfg,struct tplg_elem * elem)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 */
tplg_parse_tlv(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)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 */
tplg_save_tlv(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)400 int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
401 struct tplg_elem *elem,
402 struct tplg_buf *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 */
tplg_parse_control_bytes(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)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 */
tplg_save_control_bytes(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)558 int tplg_save_control_bytes(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
559 struct tplg_elem *elem,
560 struct tplg_buf *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. */
tplg_parse_control_enum(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)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 */
tplg_save_control_enum(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)698 int tplg_save_control_enum(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
699 struct tplg_elem *elem,
700 struct tplg_buf *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 */
tplg_parse_control_mixer(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)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
tplg_save_control_mixer(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)860 int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
861 struct tplg_elem *elem,
862 struct tplg_buf *dst, 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");
883 if (err >= 0 && mc->invert > 0)
884 err = tplg_save_printf(dst, pfx, "\tinvert 1\n");
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
init_ctl_hdr(snd_tplg_t * tplg,struct tplg_elem * parent,struct snd_soc_tplg_ctl_hdr * hdr,struct snd_tplg_ctl_template * t)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
tplg_add_mixer(snd_tplg_t * tplg,struct snd_tplg_mixer_template * mixer,struct tplg_elem ** e)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
tplg_add_enum(snd_tplg_t * tplg,struct snd_tplg_enum_template * enum_ctl,struct tplg_elem ** e)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
tplg_add_bytes(snd_tplg_t * tplg,struct snd_tplg_bytes_template * bytes_ctl,struct tplg_elem ** e)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
tplg_add_mixer_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)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
tplg_add_enum_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)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
tplg_add_bytes_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)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
tplg_decode_control_mixer1(snd_tplg_t * tplg,struct list_head * heap,struct snd_tplg_mixer_template * mt,size_t pos,void * bin,size_t size)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
tplg_decode_control_mixer(snd_tplg_t * tplg,size_t pos,struct snd_soc_tplg_hdr * hdr,void * bin,size_t size)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
tplg_decode_control_enum1(snd_tplg_t * tplg,struct list_head * heap,struct snd_tplg_enum_template * et,size_t pos,struct snd_soc_tplg_enum_control * ec)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
tplg_decode_control_enum(snd_tplg_t * tplg,size_t pos,struct snd_soc_tplg_hdr * hdr,void * bin,size_t size)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
tplg_decode_control_bytes1(snd_tplg_t * tplg,struct snd_tplg_bytes_template * bt,size_t pos,void * bin,size_t size)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
tplg_decode_control_bytes(snd_tplg_t * tplg,size_t pos,struct snd_soc_tplg_hdr * hdr,void * bin,size_t size)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 }
1526