• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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