• 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 RATE(v) [SND_PCM_RATE_##v] = #v
24 
25 static const char *const snd_pcm_rate_names[] = {
26 	RATE(5512),
27 	RATE(8000),
28 	RATE(11025),
29 	RATE(16000),
30 	RATE(22050),
31 	RATE(32000),
32 	RATE(44100),
33 	RATE(48000),
34 	RATE(64000),
35 	RATE(88200),
36 	RATE(96000),
37 	RATE(176400),
38 	RATE(192000),
39 	RATE(CONTINUOUS),
40 	RATE(KNOT),
41 };
42 
lookup_pcm_dai_stream(struct list_head * base,const char * id)43 struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
44 {
45 	struct list_head *pos;
46 	struct tplg_elem *elem;
47 	struct snd_soc_tplg_pcm *pcm;
48 
49 	list_for_each(pos, base) {
50 
51 		elem = list_entry(pos, struct tplg_elem, list);
52 		if (elem->type != SND_TPLG_TYPE_PCM)
53 			return NULL;
54 
55 		pcm = elem->pcm;
56 
57 		if (pcm && !strcmp(pcm->dai_name, id))
58 			return elem;
59 	}
60 
61 	return NULL;
62 }
63 
64 /* copy referenced caps to the parent (pcm or be dai) */
copy_stream_caps(const char * id ATTRIBUTE_UNUSED,struct snd_soc_tplg_stream_caps * caps,struct tplg_elem * ref_elem)65 static void copy_stream_caps(const char *id ATTRIBUTE_UNUSED,
66 			     struct snd_soc_tplg_stream_caps *caps,
67 			     struct tplg_elem *ref_elem)
68 {
69 	struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps;
70 
71 	tplg_dbg("Copy pcm caps (%ld bytes) from '%s' to '%s'",
72 		sizeof(*caps), ref_elem->id, id);
73 
74 	*caps =  *ref_caps;
75 }
76 
77 /* find and copy the referenced stream caps */
tplg_build_stream_caps(snd_tplg_t * tplg,const char * id,int index,struct snd_soc_tplg_stream_caps * caps)78 static int tplg_build_stream_caps(snd_tplg_t *tplg,
79 				  const char *id, int index,
80 				  struct snd_soc_tplg_stream_caps *caps)
81 {
82 	struct tplg_elem *ref_elem = NULL;
83 	unsigned int i;
84 
85 	for (i = 0; i < 2; i++) {
86 		ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
87 			caps[i].name, SND_TPLG_TYPE_STREAM_CAPS, index);
88 
89 		if (ref_elem != NULL)
90 			copy_stream_caps(id, &caps[i], ref_elem);
91 	}
92 
93 	return 0;
94 }
95 
96 /* build a PCM (FE DAI & DAI link) element */
build_pcm(snd_tplg_t * tplg,struct tplg_elem * elem)97 static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem)
98 {
99 	struct tplg_ref *ref;
100 	struct list_head *base, *pos;
101 	int err;
102 
103 	err = tplg_build_stream_caps(tplg, elem->id, elem->index,
104 						elem->pcm->caps);
105 	if (err < 0)
106 		return err;
107 
108 	/* merge private data from the referenced data elements */
109 	base = &elem->ref_list;
110 	list_for_each(pos, base) {
111 
112 		ref = list_entry(pos, struct tplg_ref, list);
113 		if (ref->type == SND_TPLG_TYPE_DATA) {
114 			err = tplg_copy_data(tplg, elem, ref);
115 			if (err < 0)
116 				return err;
117 		}
118 		if (!ref->elem) {
119 			SNDERR("cannot find '%s' referenced by"
120 				" PCM '%s'", ref->id, elem->id);
121 			return -EINVAL;
122 		}
123 	}
124 
125 	return 0;
126 }
127 
128 /* build all PCM (FE DAI & DAI link) elements */
tplg_build_pcms(snd_tplg_t * tplg,unsigned int type)129 int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type)
130 {
131 	struct list_head *base, *pos;
132 	struct tplg_elem *elem;
133 	int err = 0;
134 
135 	base = &tplg->pcm_list;
136 	list_for_each(pos, base) {
137 
138 		elem = list_entry(pos, struct tplg_elem, list);
139 		if (elem->type != type) {
140 			SNDERR("invalid elem '%s'", elem->id);
141 			return -EINVAL;
142 		}
143 
144 		err = build_pcm(tplg, elem);
145 		if (err < 0)
146 			return err;
147 
148 		/* add PCM to manifest */
149 		tplg->manifest.pcm_elems++;
150 	}
151 
152 	return 0;
153 }
154 
155 /* build a physical DAI */
tplg_build_dai(snd_tplg_t * tplg,struct tplg_elem * elem)156 static int tplg_build_dai(snd_tplg_t *tplg, struct tplg_elem *elem)
157 {
158 	struct tplg_ref *ref;
159 	struct list_head *base, *pos;
160 	int err = 0;
161 
162 	/* get playback & capture stream caps */
163 	err = tplg_build_stream_caps(tplg, elem->id, elem->index,
164 						elem->dai->caps);
165 	if (err < 0)
166 		return err;
167 
168 	/* get private data */
169 	base = &elem->ref_list;
170 	list_for_each(pos, base) {
171 
172 		ref = list_entry(pos, struct tplg_ref, list);
173 
174 		if (ref->type == SND_TPLG_TYPE_DATA) {
175 			err = tplg_copy_data(tplg, elem, ref);
176 			if (err < 0)
177 				return err;
178 		}
179 	}
180 
181 	/* add DAI to manifest */
182 	tplg->manifest.dai_elems++;
183 
184 	return 0;
185 }
186 
187 /* build physical DAIs*/
tplg_build_dais(snd_tplg_t * tplg,unsigned int type)188 int tplg_build_dais(snd_tplg_t *tplg, unsigned int type)
189 {
190 	struct list_head *base, *pos;
191 	struct tplg_elem *elem;
192 	int err = 0;
193 
194 	base = &tplg->dai_list;
195 	list_for_each(pos, base) {
196 
197 		elem = list_entry(pos, struct tplg_elem, list);
198 		if (elem->type != type) {
199 			SNDERR("invalid elem '%s'", elem->id);
200 			return -EINVAL;
201 		}
202 
203 		err = tplg_build_dai(tplg, elem);
204 		if (err < 0)
205 			return err;
206 	}
207 
208 	return 0;
209 }
210 
tplg_build_stream_cfg(snd_tplg_t * tplg,struct snd_soc_tplg_stream * stream,int num_streams,int index)211 static int tplg_build_stream_cfg(snd_tplg_t *tplg,
212 				 struct snd_soc_tplg_stream *stream,
213 				 int num_streams, int index)
214 {
215 	struct snd_soc_tplg_stream *strm;
216 	struct tplg_elem *ref_elem;
217 	int i;
218 
219 	for (i = 0; i < num_streams; i++) {
220 		strm = stream + i;
221 		ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
222 			strm->name, SND_TPLG_TYPE_STREAM_CONFIG, index);
223 
224 		if (ref_elem && ref_elem->stream_cfg)
225 			*strm = *ref_elem->stream_cfg;
226 	}
227 
228 	return 0;
229 }
230 
build_link(snd_tplg_t * tplg,struct tplg_elem * elem)231 static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem)
232 {
233 	struct snd_soc_tplg_link_config *link = elem->link;
234 	struct tplg_ref *ref;
235 	struct list_head *base, *pos;
236 	int num_hw_configs = 0, err = 0;
237 
238 	err = tplg_build_stream_cfg(tplg, link->stream,
239 				    link->num_streams, elem->index);
240 	if (err < 0)
241 		return err;
242 
243 	/* hw configs & private data */
244 	base = &elem->ref_list;
245 	list_for_each(pos, base) {
246 
247 		ref = list_entry(pos, struct tplg_ref, list);
248 
249 		switch (ref->type) {
250 		case SND_TPLG_TYPE_HW_CONFIG:
251 			ref->elem = tplg_elem_lookup(&tplg->hw_cfg_list,
252 				ref->id, SND_TPLG_TYPE_HW_CONFIG, elem->index);
253 			if (!ref->elem) {
254 				SNDERR("cannot find HW config '%s'"
255 				       " referenced by link '%s'",
256 				       ref->id, elem->id);
257 				return -EINVAL;
258 			}
259 
260 			memcpy(&link->hw_config[num_hw_configs],
261 				ref->elem->hw_cfg,
262 				sizeof(struct snd_soc_tplg_hw_config));
263 			num_hw_configs++;
264 			break;
265 
266 		case SND_TPLG_TYPE_DATA: /* merge private data */
267 			err = tplg_copy_data(tplg, elem, ref);
268 			if (err < 0)
269 				return err;
270 			link = elem->link; /* realloc */
271 			break;
272 
273 		default:
274 			break;
275 		}
276 	}
277 
278 	/* add link to manifest */
279 	tplg->manifest.dai_link_elems++;
280 
281 	return 0;
282 }
283 
284 /* build physical DAI link configurations */
tplg_build_links(snd_tplg_t * tplg,unsigned int type)285 int tplg_build_links(snd_tplg_t *tplg, unsigned int type)
286 {
287 	struct list_head *base, *pos;
288 	struct tplg_elem *elem;
289 	int err = 0;
290 
291 	switch (type) {
292 	case SND_TPLG_TYPE_LINK:
293 	case SND_TPLG_TYPE_BE:
294 		base = &tplg->be_list;
295 		break;
296 	case SND_TPLG_TYPE_CC:
297 		base = &tplg->cc_list;
298 		break;
299 	default:
300 		return -EINVAL;
301 	}
302 
303 	list_for_each(pos, base) {
304 
305 		elem = list_entry(pos, struct tplg_elem, list);
306 		err =  build_link(tplg, elem);
307 		if (err < 0)
308 			return err;
309 	}
310 
311 	return 0;
312 }
313 
split_format(struct snd_soc_tplg_stream_caps * caps,char * str)314 static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
315 {
316 	char *s = NULL;
317 	snd_pcm_format_t format;
318 	int i = 0;
319 
320 	s = strtok(str, ",");
321 	while ((s != NULL) && (i < SND_SOC_TPLG_MAX_FORMATS)) {
322 		format = snd_pcm_format_value(s);
323 		if (format == SND_PCM_FORMAT_UNKNOWN) {
324 			SNDERR("unsupported stream format %s", s);
325 			return -EINVAL;
326 		}
327 
328 		caps->formats |= 1ull << format;
329 		s = strtok(NULL, ", ");
330 		i++;
331 	}
332 
333 	return 0;
334 }
335 
get_rate_value(const char * name)336 static int get_rate_value(const char* name)
337 {
338 	int rate;
339 	for (rate = 0; rate <= SND_PCM_RATE_LAST; rate++) {
340 		if (snd_pcm_rate_names[rate] &&
341 		    strcasecmp(name, snd_pcm_rate_names[rate]) == 0) {
342 			return rate;
343 		}
344 	}
345 
346 	return SND_PCM_RATE_UNKNOWN;
347 }
348 
get_rate_name(int rate)349 static const char *get_rate_name(int rate)
350 {
351 	if (rate >= 0 && rate <= SND_PCM_RATE_LAST)
352 		return snd_pcm_rate_names[rate];
353 	return NULL;
354 }
355 
split_rate(struct snd_soc_tplg_stream_caps * caps,char * str)356 static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str)
357 {
358 	char *s = NULL;
359 	snd_pcm_rates_t rate;
360 	int i = 0;
361 
362 	s = strtok(str, ",");
363 	while (s) {
364 		rate = get_rate_value(s);
365 
366 		if (rate == SND_PCM_RATE_UNKNOWN) {
367 			SNDERR("unsupported stream rate %s", s);
368 			return -EINVAL;
369 		}
370 
371 		caps->rates |= 1 << rate;
372 		s = strtok(NULL, ", ");
373 		i++;
374 	}
375 
376 	return 0;
377 }
378 
parse_unsigned(snd_config_t * n,void * dst)379 static int parse_unsigned(snd_config_t *n, void *dst)
380 {
381 	int ival;
382 
383 	if (tplg_get_integer(n, &ival, 0) < 0)
384 		return -EINVAL;
385 
386 	unaligned_put32(dst, ival);
387 #if TPLG_DEBUG
388 	{
389 		const char *id;
390 		if (snd_config_get_id(n, &id) >= 0)
391 			tplg_dbg("\t\t%s: %d", id, ival);
392 	}
393 #endif
394 	return 0;
395 }
396 
397 /* Parse pcm stream capabilities */
tplg_parse_stream_caps(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)398 int tplg_parse_stream_caps(snd_tplg_t *tplg,
399 			   snd_config_t *cfg,
400 			   void *private ATTRIBUTE_UNUSED)
401 {
402 	struct snd_soc_tplg_stream_caps *sc;
403 	struct tplg_elem *elem;
404 	snd_config_iterator_t i, next;
405 	snd_config_t *n;
406 	const char *id, *val;
407 	char *s;
408 	int err;
409 
410 	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CAPS);
411 	if (!elem)
412 		return -ENOMEM;
413 
414 	sc = elem->stream_caps;
415 	sc->size = elem->size;
416 	snd_strlcpy(sc->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
417 
418 	tplg_dbg(" PCM Capabilities: %s", elem->id);
419 
420 	snd_config_for_each(i, next, cfg) {
421 		n = snd_config_iterator_entry(i);
422 		if (snd_config_get_id(n, &id) < 0)
423 			continue;
424 
425 		/* skip comments */
426 		if (strcmp(id, "comment") == 0)
427 			continue;
428 		if (id[0] == '#')
429 			continue;
430 
431 		if (strcmp(id, "formats") == 0) {
432 			if (snd_config_get_string(n, &val) < 0)
433 				return -EINVAL;
434 
435 			s = strdup(val);
436 			if (s == NULL)
437 				return -ENOMEM;
438 
439 			err = split_format(sc, s);
440 			free(s);
441 
442 			if (err < 0)
443 				return err;
444 
445 			tplg_dbg("\t\t%s: %s", id, val);
446 			continue;
447 		}
448 
449 		if (strcmp(id, "rates") == 0) {
450 			if (snd_config_get_string(n, &val) < 0)
451 				return -EINVAL;
452 
453 			s = strdup(val);
454 			if (!s)
455 				return -ENOMEM;
456 
457 			err = split_rate(sc, s);
458 			free(s);
459 
460 			if (err < 0)
461 				return err;
462 
463 			tplg_dbg("\t\t%s: %s", id, val);
464 			continue;
465 		}
466 
467 		if (strcmp(id, "rate_min") == 0) {
468 			if (parse_unsigned(n, &sc->rate_min))
469 				return -EINVAL;
470 			continue;
471 		}
472 
473 		if (strcmp(id, "rate_max") == 0) {
474 			if (parse_unsigned(n, &sc->rate_max))
475 				return -EINVAL;
476 			continue;
477 		}
478 
479 		if (strcmp(id, "channels_min") == 0) {
480 			if (parse_unsigned(n, &sc->channels_min))
481 				return -EINVAL;
482 			continue;
483 		}
484 
485 		if (strcmp(id, "channels_max") == 0) {
486 			if (parse_unsigned(n, &sc->channels_max))
487 				return -EINVAL;
488 			continue;
489 		}
490 
491 		if (strcmp(id, "periods_min") == 0) {
492 			if (parse_unsigned(n, &sc->periods_min))
493 				return -EINVAL;
494 			continue;
495 		}
496 
497 		if (strcmp(id, "periods_max") == 0) {
498 			if (parse_unsigned(n, &sc->periods_max))
499 				return -EINVAL;
500 			continue;
501 		}
502 
503 		if (strcmp(id, "period_size_min") == 0) {
504 			if (parse_unsigned(n, &sc->period_size_min))
505 				return -EINVAL;
506 			continue;
507 		}
508 
509 		if (strcmp(id, "period_size_max") == 0) {
510 			if (parse_unsigned(n, &sc->period_size_max))
511 				return -EINVAL;
512 			continue;
513 		}
514 
515 		if (strcmp(id, "buffer_size_min") == 0) {
516 			if (parse_unsigned(n, &sc->buffer_size_min))
517 				return -EINVAL;
518 			continue;
519 		}
520 
521 		if (strcmp(id, "buffer_size_max") == 0) {
522 			if (parse_unsigned(n, &sc->buffer_size_max))
523 				return -EINVAL;
524 			continue;
525 		}
526 
527 		if (strcmp(id, "sig_bits") == 0) {
528 			if (parse_unsigned(n, &sc->sig_bits))
529 				return -EINVAL;
530 			continue;
531 		}
532 
533 	}
534 
535 	return 0;
536 }
537 
538 /* save stream caps */
tplg_save_stream_caps(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)539 int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
540 			  struct tplg_elem *elem,
541 			  struct tplg_buf *dst, const char *pfx)
542 {
543 	struct snd_soc_tplg_stream_caps *sc = elem->stream_caps;
544 	const char *s;
545 	unsigned int i;
546 	int err, first;
547 
548 	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
549 	if (err >= 0 && sc->formats) {
550 		err = tplg_save_printf(dst, pfx, "\tformats '");
551 		first = 1;
552 		for (i = 0; err >= 0 && i <= SND_PCM_FORMAT_LAST; i++) {
553 			if (sc->formats & (1ULL << i)) {
554 				s = snd_pcm_format_name(i);
555 				err = tplg_save_printf(dst, NULL, "%s%s",
556 						       !first ? ", " : "", s);
557 				first = 0;
558 			}
559 		}
560 		if (err >= 0)
561 			err = tplg_save_printf(dst, NULL, "'\n");
562 	}
563 	if (err >= 0 && sc->rates) {
564 		err = tplg_save_printf(dst, pfx, "\trates '");
565 		first = 1;
566 		for (i = 0; err >= 0 && i <= SND_PCM_RATE_LAST; i++) {
567 			if (sc->rates & (1ULL << i)) {
568 				s = get_rate_name(i);
569 				err = tplg_save_printf(dst, NULL, "%s%s",
570 						       !first ? ", " : "", s);
571 				first = 0;
572 			}
573 		}
574 		if (err >= 0)
575 			err = tplg_save_printf(dst, NULL, "'\n");
576 	}
577 	if (err >= 0 && sc->rate_min)
578 		err = tplg_save_printf(dst, pfx, "\trate_min %u\n",
579 				       sc->rate_min);
580 	if (err >= 0 && sc->rate_max)
581 		err = tplg_save_printf(dst, pfx, "\trate_max %u\n",
582 				       sc->rate_max);
583 	if (err >= 0 && sc->channels_min)
584 		err = tplg_save_printf(dst, pfx, "\tchannels_min %u\n",
585 				       sc->channels_min);
586 	if (err >= 0 && sc->channels_max)
587 		err = tplg_save_printf(dst, pfx, "\tchannels_max %u\n",
588 				       sc->channels_max);
589 	if (err >= 0 && sc->periods_min)
590 		err = tplg_save_printf(dst, pfx, "\tperiods_min %u\n",
591 				       sc->periods_min);
592 	if (err >= 0 && sc->periods_max)
593 		err = tplg_save_printf(dst, pfx, "\tperiods_max %u\n",
594 				       sc->periods_max);
595 	if (err >= 0 && sc->period_size_min)
596 		err = tplg_save_printf(dst, pfx, "\tperiod_size_min %u\n",
597 				       sc->period_size_min);
598 	if (err >= 0 && sc->period_size_max)
599 		err = tplg_save_printf(dst, pfx, "\tperiod_size_max %u\n",
600 				       sc->period_size_max);
601 	if (err >= 0 && sc->buffer_size_min)
602 		err = tplg_save_printf(dst, pfx, "\tbuffer_size_min %u\n",
603 				       sc->buffer_size_min);
604 	if (err >= 0 && sc->buffer_size_max)
605 		err = tplg_save_printf(dst, pfx, "\tbuffer_size_max %u\n",
606 				       sc->buffer_size_max);
607 	if (err >= 0 && sc->sig_bits)
608 		err = tplg_save_printf(dst, pfx, "\tsig_bits %u\n",
609 				       sc->sig_bits);
610 	if (err >= 0)
611 		err = tplg_save_printf(dst, pfx, "}\n");
612 	return err;
613 }
614 
615 /* Parse the caps and config of a pcm stream */
tplg_parse_streams(snd_tplg_t * tplg ATTRIBUTE_UNUSED,snd_config_t * cfg,void * private)616 static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
617 			      snd_config_t *cfg, void *private)
618 {
619 	snd_config_iterator_t i, next;
620 	snd_config_t *n;
621 	struct tplg_elem *elem = private;
622 	struct snd_soc_tplg_pcm *pcm;
623 	struct snd_soc_tplg_dai *dai;
624 	void *playback, *capture;
625 	struct snd_soc_tplg_stream_caps *caps;
626 	const char *id, *value;
627 	int stream;
628 
629 	snd_config_get_id(cfg, &id);
630 
631 	tplg_dbg("\t%s:", id);
632 
633 	switch (elem->type) {
634 	case SND_TPLG_TYPE_PCM:
635 		pcm = elem->pcm;
636 		playback = &pcm->playback;
637 		capture = &pcm->capture;
638 		caps = pcm->caps;
639 		break;
640 
641 	case SND_TPLG_TYPE_DAI:
642 		dai = elem->dai;
643 		playback = &dai->playback;
644 		capture = &dai->capture;
645 		caps = dai->caps;
646 		break;
647 
648 	default:
649 		return -EINVAL;
650 	}
651 
652 	if (strcmp(id, "playback") == 0) {
653 		stream = SND_SOC_TPLG_STREAM_PLAYBACK;
654 		unaligned_put32(playback, 1);
655 	} else if (strcmp(id, "capture") == 0) {
656 		stream = SND_SOC_TPLG_STREAM_CAPTURE;
657 		unaligned_put32(capture, 1);
658 	} else
659 		return -EINVAL;
660 
661 	snd_config_for_each(i, next, cfg) {
662 
663 		n = snd_config_iterator_entry(i);
664 
665 		/* get id */
666 		if (snd_config_get_id(n, &id) < 0)
667 			continue;
668 
669 		if (strcmp(id, "capabilities") == 0) {
670 			if (snd_config_get_string(n, &value) < 0)
671 				continue;
672 			/* store stream caps name, to find and merge
673 			 * the caps in building phase.
674 			 */
675 			snd_strlcpy(caps[stream].name, value,
676 				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
677 
678 			tplg_dbg("\t\t%s\n\t\t\t%s", id, value);
679 			continue;
680 		}
681 	}
682 
683 	return 0;
684 }
685 
686 /* Save the caps and config of a pcm stream */
tplg_save_streams(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)687 int tplg_save_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
688 		      struct tplg_elem *elem,
689 		      struct tplg_buf *dst, const char *pfx)
690 {
691 	static const char *stream_ids[2] = {
692 		"playback",
693 		"capture"
694 	};
695 	static unsigned int stream_types[2] = {
696 		SND_SOC_TPLG_STREAM_PLAYBACK,
697 		SND_SOC_TPLG_STREAM_CAPTURE
698 	};
699 	struct snd_soc_tplg_stream_caps *caps;
700 	unsigned int streams[2], stream;
701 	const char *s;
702 	int err;
703 
704 	switch (elem->type) {
705 	case SND_TPLG_TYPE_PCM:
706 		streams[0] = elem->pcm->playback;
707 		streams[1] = elem->pcm->capture;
708 		caps = elem->pcm->caps;
709 		break;
710 	case SND_TPLG_TYPE_DAI:
711 		streams[0] = elem->dai->playback;
712 		streams[1] = elem->dai->capture;
713 		caps = elem->dai->caps;
714 		break;
715 	default:
716 		return -EINVAL;
717 	}
718 
719 	for (stream = 0; stream < 2; stream++) {
720 		if (streams[stream] == 0)
721 			continue;
722 		if (!caps)
723 			continue;
724 		s = caps[stream_types[stream]].name;
725 		if (s[0] == '\0')
726 			continue;
727 		err = tplg_save_printf(dst, pfx, "pcm.%s {\n", stream_ids[stream]);
728 		if (err < 0)
729 			return err;
730 		err = tplg_save_printf(dst, pfx, "\tcapabilities '%s'\n", s);
731 		if (err < 0)
732 			return err;
733 		err = tplg_save_printf(dst, pfx, "}\n");
734 		if (err < 0)
735 			return err;
736 	}
737 
738 	return 0;
739 }
740 
741 /* Parse name and id of a front-end DAI (ie. cpu dai of a FE DAI link) */
tplg_parse_fe_dai(snd_tplg_t * tplg ATTRIBUTE_UNUSED,snd_config_t * cfg,void * private)742 static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
743 			     snd_config_t *cfg, void *private)
744 {
745 	struct tplg_elem *elem = private;
746 	struct snd_soc_tplg_pcm *pcm = elem->pcm;
747 	snd_config_iterator_t i, next;
748 	snd_config_t *n;
749 	const char *id;
750 	unsigned int dai_id;
751 
752 	snd_config_get_id(cfg, &id);
753 	tplg_dbg("\t\tFE DAI %s:", id);
754 	snd_strlcpy(pcm->dai_name, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
755 
756 	snd_config_for_each(i, next, cfg) {
757 
758 		n = snd_config_iterator_entry(i);
759 
760 		/* get id */
761 		if (snd_config_get_id(n, &id) < 0)
762 			continue;
763 
764 		if (strcmp(id, "id") == 0) {
765 			if (tplg_get_unsigned(n, &dai_id, 0)) {
766 				SNDERR("invalid fe dai ID");
767 				return -EINVAL;
768 			}
769 
770 			unaligned_put32(&pcm->dai_id, dai_id);
771 			tplg_dbg("\t\t\tindex: %d", dai_id);
772 		}
773 	}
774 
775 	return 0;
776 }
777 
778 /* Save the caps and config of a pcm stream */
tplg_save_fe_dai(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)779 int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
780 		     struct tplg_elem *elem,
781 		     struct tplg_buf *dst, const char *pfx)
782 {
783 	struct snd_soc_tplg_pcm *pcm = elem->pcm;
784 	int err = 0;
785 
786 	if (strlen(pcm->dai_name))
787 		err = tplg_save_printf(dst, pfx, "dai.'%s'.id %u\n", pcm->dai_name, pcm->dai_id);
788 	else if (pcm->dai_id > 0)
789 		err = tplg_save_printf(dst, pfx, "dai.0.id %u\n", pcm->dai_id);
790 	return err;
791 }
792 
793 /* parse a flag bit of the given mask */
parse_flag(snd_config_t * n,unsigned int mask_in,void * mask,void * flags)794 static int parse_flag(snd_config_t *n, unsigned int mask_in,
795 		      void *mask, void *flags)
796 {
797 	int ret;
798 
799 	ret = snd_config_get_bool(n);
800 	if (ret < 0)
801 		return ret;
802 
803 	unaligned_put32(mask, unaligned_get32(mask) | mask_in);
804 	if (ret)
805 		unaligned_put32(flags, unaligned_get32(flags) | mask_in);
806 	else
807 		unaligned_put32(flags, unaligned_get32(flags) & (~mask_in));
808 
809 	return 0;
810 }
811 
save_flags(unsigned int flags,unsigned int mask,struct tplg_buf * dst,const char * pfx)812 static int save_flags(unsigned int flags, unsigned int mask,
813 		      struct tplg_buf *dst, const char *pfx)
814 {
815 	static unsigned int flag_masks[3] = {
816 		SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES,
817 		SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS,
818 		SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS,
819 	};
820 	static const char *flag_ids[3] = {
821 		"symmetric_rates",
822 		"symmetric_channels",
823 		"symmetric_sample_bits",
824 	};
825 	unsigned int i;
826 	int err = 0;
827 
828 	for (i = 0; err >= 0 && i < ARRAY_SIZE(flag_masks); i++) {
829 		if (mask & flag_masks[i]) {
830 			unsigned int v = (flags & flag_masks[i]) ? 1 : 0;
831 			err = tplg_save_printf(dst, pfx, "%s %u\n",
832 					       flag_ids[i], v);
833 		}
834 	}
835 	return err;
836 }
837 
838 /* Parse PCM (for front end DAI & DAI link) in text conf file */
tplg_parse_pcm(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)839 int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg,
840 		   void *private ATTRIBUTE_UNUSED)
841 {
842 	struct snd_soc_tplg_pcm *pcm;
843 	struct tplg_elem *elem;
844 	snd_config_iterator_t i, next;
845 	snd_config_t *n;
846 	const char *id;
847 	int err, ival;
848 
849 	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_PCM);
850 	if (!elem)
851 		return -ENOMEM;
852 
853 	pcm = elem->pcm;
854 	pcm->size = elem->size;
855 	snd_strlcpy(pcm->pcm_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
856 
857 	tplg_dbg(" PCM: %s", elem->id);
858 
859 	snd_config_for_each(i, next, cfg) {
860 
861 		n = snd_config_iterator_entry(i);
862 		if (snd_config_get_id(n, &id) < 0)
863 			continue;
864 
865 		/* skip comments */
866 		if (strcmp(id, "comment") == 0)
867 			continue;
868 		if (id[0] == '#')
869 			continue;
870 
871 		if (strcmp(id, "id") == 0) {
872 			if (parse_unsigned(n, &pcm->pcm_id))
873 				return -EINVAL;
874 			continue;
875 		}
876 
877 		if (strcmp(id, "pcm") == 0) {
878 			err = tplg_parse_compound(tplg, n,
879 				tplg_parse_streams, elem);
880 			if (err < 0)
881 				return err;
882 			continue;
883 		}
884 
885 		if (strcmp(id, "compress") == 0) {
886 			ival = snd_config_get_bool(n);
887 			if (ival < 0)
888 				return -EINVAL;
889 
890 			pcm->compress = ival;
891 
892 			tplg_dbg("\t%s: %d", id, ival);
893 			continue;
894 		}
895 
896 		if (strcmp(id, "dai") == 0) {
897 			err = tplg_parse_compound(tplg, n,
898 				tplg_parse_fe_dai, elem);
899 			if (err < 0)
900 				return err;
901 			continue;
902 		}
903 
904 		/* flags */
905 		if (strcmp(id, "symmetric_rates") == 0) {
906 			err = parse_flag(n,
907 				SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES,
908 				&pcm->flag_mask, &pcm->flags);
909 			if (err < 0)
910 				return err;
911 			continue;
912 		}
913 
914 		if (strcmp(id, "symmetric_channels") == 0) {
915 			err = parse_flag(n,
916 				SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS,
917 				&pcm->flag_mask, &pcm->flags);
918 			if (err < 0)
919 				return err;
920 			continue;
921 		}
922 
923 		if (strcmp(id, "symmetric_sample_bits") == 0) {
924 			err = parse_flag(n,
925 				SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS,
926 				&pcm->flag_mask, &pcm->flags);
927 			if (err < 0)
928 				return err;
929 			continue;
930 		}
931 
932 		/* private data */
933 		if (strcmp(id, "data") == 0) {
934 			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
935 			if (err < 0)
936 				return err;
937 			continue;
938 		}
939 	}
940 
941 	return 0;
942 }
943 
944 /* save PCM */
tplg_save_pcm(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)945 int tplg_save_pcm(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
946 		  struct tplg_elem *elem,
947 		  struct tplg_buf *dst, const char *pfx)
948 {
949 	struct snd_soc_tplg_pcm *pcm = elem->pcm;
950 	char pfx2[16];
951 	int err;
952 
953 	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
954 	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
955 	if (err >= 0 && elem->index)
956 		err = tplg_save_printf(dst, pfx, "\tindex %u\n",
957 				       elem->index);
958 	if (err >= 0 && pcm->pcm_id)
959 		err = tplg_save_printf(dst, pfx, "\tid %u\n",
960 				       pcm->pcm_id);
961 	if (err >= 0 && pcm->compress)
962 		err = tplg_save_printf(dst, pfx, "\tcompress 1\n");
963 	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
964 	if (err >= 0)
965 		err = tplg_save_fe_dai(tplg, elem, dst, pfx2);
966 	if (err >= 0)
967 		err = tplg_save_streams(tplg, elem, dst, pfx2);
968 	if (err >= 0)
969 		err = save_flags(pcm->flags, pcm->flag_mask, dst, pfx);
970 	if (err >= 0)
971 		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
972 				     "data", dst, pfx2);
973 	if (err >= 0)
974 		err = tplg_save_printf(dst, pfx, "}\n");
975 	return err;
976 }
977 
978 /* Parse physical DAI */
tplg_parse_dai(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)979 int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg,
980 		   void *private ATTRIBUTE_UNUSED)
981 {
982 	struct snd_soc_tplg_dai *dai;
983 	struct tplg_elem *elem;
984 	snd_config_iterator_t i, next;
985 	snd_config_t *n;
986 	const char *id;
987 	int err;
988 
989 	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAI);
990 	if (!elem)
991 		return -ENOMEM;
992 
993 	dai = elem->dai;
994 	dai->size = elem->size;
995 	snd_strlcpy(dai->dai_name, elem->id,
996 		SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
997 
998 	tplg_dbg(" DAI: %s", elem->id);
999 
1000 	snd_config_for_each(i, next, cfg) {
1001 
1002 		n = snd_config_iterator_entry(i);
1003 		if (snd_config_get_id(n, &id) < 0)
1004 			continue;
1005 
1006 		/* skip comments */
1007 		if (strcmp(id, "comment") == 0)
1008 			continue;
1009 		if (id[0] == '#')
1010 			continue;
1011 
1012 		if (strcmp(id, "id") == 0) {
1013 			if (parse_unsigned(n, &dai->dai_id))
1014 				return -EINVAL;
1015 			continue;
1016 		}
1017 
1018 		if (strcmp(id, "playback") == 0) {
1019 			if (parse_unsigned(n, &dai->playback))
1020 				return -EINVAL;
1021 			continue;
1022 		}
1023 
1024 
1025 		if (strcmp(id, "capture") == 0) {
1026 			if (parse_unsigned(n, &dai->capture))
1027 				return -EINVAL;
1028 			continue;
1029 		}
1030 
1031 
1032 		/* stream capabilities */
1033 		if (strcmp(id, "pcm") == 0) {
1034 			err = tplg_parse_compound(tplg, n,
1035 				tplg_parse_streams, elem);
1036 			if (err < 0)
1037 				return err;
1038 			continue;
1039 		}
1040 
1041 		/* flags */
1042 		if (strcmp(id, "symmetric_rates") == 0) {
1043 			err = parse_flag(n,
1044 				SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES,
1045 				&dai->flag_mask, &dai->flags);
1046 			if (err < 0)
1047 				return err;
1048 			continue;
1049 		}
1050 
1051 		if (strcmp(id, "symmetric_channels") == 0) {
1052 			err = parse_flag(n,
1053 				SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS,
1054 				&dai->flag_mask, &dai->flags);
1055 			if (err < 0)
1056 				return err;
1057 			continue;
1058 		}
1059 
1060 		if (strcmp(id, "symmetric_sample_bits") == 0) {
1061 			err = parse_flag(n,
1062 				SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS,
1063 				&dai->flag_mask, &dai->flags);
1064 			if (err < 0)
1065 				return err;
1066 			continue;
1067 		}
1068 
1069 		/* private data */
1070 		if (strcmp(id, "data") == 0) {
1071 			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
1072 			if (err < 0)
1073 				return err;
1074 			continue;
1075 		}
1076 	}
1077 
1078 	return 0;
1079 }
1080 
1081 /* save DAI */
tplg_save_dai(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1082 int tplg_save_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1083 		  struct tplg_elem *elem,
1084 		  struct tplg_buf *dst, const char *pfx)
1085 {
1086 	struct snd_soc_tplg_dai *dai = elem->dai;
1087 	char pfx2[16];
1088 	int err;
1089 
1090 	if (!dai)
1091 		return 0;
1092 	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1093 	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1094 	if (err >= 0 && elem->index)
1095 		err = tplg_save_printf(dst, pfx, "\tindex %u\n",
1096 				       elem->index);
1097 	if (err >= 0 && dai->dai_id)
1098 		err = tplg_save_printf(dst, pfx, "\tid %u\n",
1099 				       dai->dai_id);
1100 	if (err >= 0 && dai->playback)
1101 		err = tplg_save_printf(dst, pfx, "\tplayback %u\n",
1102 				       dai->playback);
1103 	if (err >= 0 && dai->capture)
1104 		err = tplg_save_printf(dst, pfx, "\tcapture %u\n",
1105 				       dai->capture);
1106 	if (err >= 0)
1107 		err = tplg_save_streams(tplg, elem, dst, pfx2);
1108 	if (err >= 0)
1109 		err = save_flags(dai->flags, dai->flag_mask, dst, pfx);
1110 	if (err >= 0)
1111 		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
1112 				     "data", dst, pfx2);
1113 	if (err >= 0)
1114 		err = tplg_save_printf(dst, pfx, "}\n");
1115 	return err;
1116 }
1117 
1118 /* parse physical link runtime supported HW configs in text conf file */
parse_hw_config_refs(snd_tplg_t * tplg ATTRIBUTE_UNUSED,snd_config_t * cfg,struct tplg_elem * elem)1119 static int parse_hw_config_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1120 				snd_config_t *cfg,
1121 				struct tplg_elem *elem)
1122 {
1123 	struct snd_soc_tplg_link_config *link = elem->link;
1124 	int err;
1125 
1126 	err = tplg_parse_refs(cfg, elem, SND_TPLG_TYPE_HW_CONFIG);
1127 	if (err < 0)
1128 		return err;
1129 	link->num_hw_configs = err;
1130 	return 0;
1131 }
1132 
1133 /* Parse a physical link element in text conf file */
tplg_parse_link(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1134 int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg,
1135 		    void *private ATTRIBUTE_UNUSED)
1136 {
1137 	struct snd_soc_tplg_link_config *link;
1138 	struct tplg_elem *elem;
1139 	snd_config_iterator_t i, next;
1140 	snd_config_t *n;
1141 	const char *id, *val = NULL;
1142 	int err;
1143 
1144 	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BE);
1145 	if (!elem)
1146 		return -ENOMEM;
1147 
1148 	link = elem->link;
1149 	link->size = elem->size;
1150 	snd_strlcpy(link->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1151 
1152 	tplg_dbg(" Link: %s", elem->id);
1153 
1154 	snd_config_for_each(i, next, cfg) {
1155 
1156 		n = snd_config_iterator_entry(i);
1157 		if (snd_config_get_id(n, &id) < 0)
1158 			continue;
1159 
1160 		/* skip comments */
1161 		if (strcmp(id, "comment") == 0)
1162 			continue;
1163 		if (id[0] == '#')
1164 			continue;
1165 
1166 		if (strcmp(id, "id") == 0) {
1167 			if (parse_unsigned(n, &link->id))
1168 				return -EINVAL;
1169 			continue;
1170 		}
1171 
1172 		if (strcmp(id, "stream_name") == 0) {
1173 			if (snd_config_get_string(n, &val) < 0)
1174 				return -EINVAL;
1175 
1176 			snd_strlcpy(link->stream_name, val,
1177 				       SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1178 			tplg_dbg("\t%s: %s", id, val);
1179 			continue;
1180 		}
1181 
1182 		if (strcmp(id, "hw_configs") == 0) {
1183 			err = parse_hw_config_refs(tplg, n, elem);
1184 			if (err < 0)
1185 				return err;
1186 			continue;
1187 		}
1188 
1189 		if (strcmp(id, "default_hw_conf_id") == 0) {
1190 			if (parse_unsigned(n, &link->default_hw_config_id))
1191 				return -EINVAL;
1192 			continue;
1193 		}
1194 
1195 		/* flags */
1196 		if (strcmp(id, "symmetric_rates") == 0) {
1197 			err = parse_flag(n,
1198 				SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES,
1199 				&link->flag_mask, &link->flags);
1200 			if (err < 0)
1201 				return err;
1202 			continue;
1203 		}
1204 
1205 		if (strcmp(id, "symmetric_channels") == 0) {
1206 			err = parse_flag(n,
1207 				SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS,
1208 				&link->flag_mask, &link->flags);
1209 			if (err < 0)
1210 				return err;
1211 			continue;
1212 		}
1213 
1214 		if (strcmp(id, "symmetric_sample_bits") == 0) {
1215 			err = parse_flag(n,
1216 				SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS,
1217 				&link->flag_mask, &link->flags);
1218 			if (err < 0)
1219 				return err;
1220 			continue;
1221 		}
1222 
1223 		/* private data */
1224 		if (strcmp(id, "data") == 0) {
1225 			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
1226 			if (err < 0)
1227 				return err;
1228 			continue;
1229 		}
1230 	}
1231 
1232 	return 0;
1233 }
1234 
1235 /* save physical link */
tplg_save_link(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1236 int tplg_save_link(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1237 		   struct tplg_elem *elem,
1238 		   struct tplg_buf *dst, const char *pfx)
1239 {
1240 	struct snd_soc_tplg_link_config *link = elem->link;
1241 	char pfx2[16];
1242 	int err;
1243 
1244 	if (!link)
1245 		return 0;
1246 	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1247 	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1248 	if (err >= 0 && elem->index)
1249 		err = tplg_save_printf(dst, pfx, "\tindex %u\n",
1250 				       elem->index);
1251 	if (err >= 0 && link->id)
1252 		err = tplg_save_printf(dst, pfx, "\tid %u\n",
1253 				       link->id);
1254 	if (err >= 0 && link->stream_name[0])
1255 		err = tplg_save_printf(dst, pfx, "\tstream_name '%s'\n",
1256 				       link->stream_name);
1257 	if (err >= 0 && link->default_hw_config_id)
1258 		err = tplg_save_printf(dst, pfx, "\tdefault_hw_conf_id %u\n",
1259 				       link->default_hw_config_id);
1260 	if (err >= 0)
1261 		err = save_flags(link->flags, link->flag_mask, dst, pfx);
1262 	if (err >= 0)
1263 		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_HW_CONFIG,
1264 				     "hw_configs", dst, pfx2);
1265 	if (err >= 0)
1266 		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
1267 				     "data", dst, pfx2);
1268 	if (err >= 0)
1269 		err = tplg_save_printf(dst, pfx, "}\n");
1270 	return err;
1271 }
1272 
1273 /* Parse cc */
tplg_parse_cc(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1274 int tplg_parse_cc(snd_tplg_t *tplg, snd_config_t *cfg,
1275 		  void *private ATTRIBUTE_UNUSED)
1276 {
1277 	struct snd_soc_tplg_link_config *link;
1278 	struct tplg_elem *elem;
1279 	snd_config_iterator_t i, next;
1280 	snd_config_t *n;
1281 	const char *id;
1282 
1283 	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_CC);
1284 	if (!elem)
1285 		return -ENOMEM;
1286 
1287 	link = elem->link;
1288 	link->size = elem->size;
1289 
1290 	tplg_dbg(" CC: %s", elem->id);
1291 
1292 	snd_config_for_each(i, next, cfg) {
1293 
1294 		n = snd_config_iterator_entry(i);
1295 		if (snd_config_get_id(n, &id) < 0)
1296 			continue;
1297 
1298 		/* skip comments */
1299 		if (strcmp(id, "comment") == 0)
1300 			continue;
1301 		if (id[0] == '#')
1302 			continue;
1303 
1304 		if (strcmp(id, "id") == 0) {
1305 			if (parse_unsigned(n, &link->id))
1306 				return -EINVAL;
1307 			continue;
1308 		}
1309 
1310 	}
1311 
1312 	return 0;
1313 }
1314 
1315 /* save CC */
tplg_save_cc(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1316 int tplg_save_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1317 		 struct tplg_elem *elem,
1318 		 struct tplg_buf *dst, const char *pfx)
1319 {
1320 	struct snd_soc_tplg_link_config *link = elem->link;
1321 	char pfx2[16];
1322 	int err;
1323 
1324 	if (!link)
1325 		return 0;
1326 	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1327 	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1328 	if (err >= 0 && elem->index)
1329 		err = tplg_save_printf(dst, pfx, "\tindex %u\n",
1330 				       elem->index);
1331 	if (err >= 0 && link->id)
1332 		err = tplg_save_printf(dst, pfx, "\tid %u\n",
1333 				       link->id);
1334 	if (err >= 0)
1335 		err = tplg_save_printf(dst, pfx, "}\n");
1336 	return err;
1337 }
1338 
1339 struct audio_hw_format {
1340 	unsigned int type;
1341 	const char *name;
1342 };
1343 
1344 static struct audio_hw_format audio_hw_formats[] = {
1345 	{
1346 		.type = SND_SOC_DAI_FORMAT_I2S,
1347 		.name = "I2S",
1348 	},
1349 	{
1350 		.type = SND_SOC_DAI_FORMAT_RIGHT_J,
1351 		.name = "RIGHT_J",
1352 	},
1353 	{
1354 		.type = SND_SOC_DAI_FORMAT_LEFT_J,
1355 		.name = "LEFT_J",
1356 	},
1357 	{
1358 		.type = SND_SOC_DAI_FORMAT_DSP_A,
1359 		.name = "DSP_A",
1360 	},
1361 	{
1362 		.type = SND_SOC_DAI_FORMAT_DSP_B,
1363 		.name = "DSP_B",
1364 	},
1365 	{
1366 		.type = SND_SOC_DAI_FORMAT_AC97,
1367 		.name = "AC97",
1368 	},
1369 	{
1370 		.type = SND_SOC_DAI_FORMAT_PDM,
1371 		.name = "PDM",
1372 	},
1373 };
1374 
get_audio_hw_format(const char * val)1375 static int get_audio_hw_format(const char *val)
1376 {
1377 	unsigned int i;
1378 
1379 	if (val[0] == '\0')
1380 		return -EINVAL;
1381 
1382 	for (i = 0; i < ARRAY_SIZE(audio_hw_formats); i++)
1383 		if (strcasecmp(audio_hw_formats[i].name, val) == 0)
1384 			return audio_hw_formats[i].type;
1385 
1386 	SNDERR("invalid audio HW format %s", val);
1387 	return -EINVAL;
1388 }
1389 
get_audio_hw_format_name(unsigned int type)1390 static const char *get_audio_hw_format_name(unsigned int type)
1391 {
1392 	unsigned int i;
1393 
1394 	for (i = 0; i < ARRAY_SIZE(audio_hw_formats); i++)
1395 		if (audio_hw_formats[i].type == type)
1396 			return audio_hw_formats[i].name;
1397 	return NULL;
1398 }
1399 
tplg_parse_hw_config(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1400 int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg,
1401 			 void *private ATTRIBUTE_UNUSED)
1402 {
1403 
1404 	struct snd_soc_tplg_hw_config *hw_cfg;
1405 	struct tplg_elem *elem;
1406 	snd_config_iterator_t i, next;
1407 	snd_config_t *n;
1408 	const char *id, *val = NULL;
1409 	int ret, ival;
1410 	bool provider_legacy;
1411 
1412 	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG);
1413 	if (!elem)
1414 		return -ENOMEM;
1415 
1416 	hw_cfg = elem->hw_cfg;
1417 	hw_cfg->size = elem->size;
1418 
1419 	tplg_dbg(" Link HW config: %s", elem->id);
1420 
1421 	snd_config_for_each(i, next, cfg) {
1422 
1423 		n = snd_config_iterator_entry(i);
1424 		if (snd_config_get_id(n, &id) < 0)
1425 			continue;
1426 
1427 		/* skip comments */
1428 		if (strcmp(id, "comment") == 0)
1429 			continue;
1430 		if (id[0] == '#')
1431 			continue;
1432 
1433 		if (strcmp(id, "id") == 0) {
1434 			if (parse_unsigned(n, &hw_cfg->id))
1435 				return -EINVAL;
1436 			continue;
1437 		}
1438 
1439 		if (strcmp(id, "format") == 0 ||
1440 		    strcmp(id, "fmt") == 0) {
1441 			if (snd_config_get_string(n, &val) < 0)
1442 				return -EINVAL;
1443 
1444 			ret = get_audio_hw_format(val);
1445 			if (ret < 0)
1446 				return ret;
1447 			hw_cfg->fmt = ret;
1448 			continue;
1449 		}
1450 
1451 		provider_legacy = false;
1452 		if (strcmp(id, "bclk_master") == 0) {
1453 			SNDERR("deprecated option %s, please use 'bclk'\n", id);
1454 			provider_legacy = true;
1455 		}
1456 
1457 		if (provider_legacy ||
1458 		    strcmp(id, "bclk") == 0) {
1459 
1460 			if (snd_config_get_string(n, &val) < 0)
1461 				return -EINVAL;
1462 
1463 			if (!strcmp(val, "master")) {
1464 				/* For backwards capability,
1465 				 * "master" == "codec is slave"
1466 				 */
1467 				SNDERR("deprecated bclk value '%s'", val);
1468 
1469 				hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC;
1470 			} else if (!strcmp(val, "codec_slave")) {
1471 				SNDERR("deprecated bclk value '%s', use 'codec_consumer'", val);
1472 
1473 				hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC;
1474 			} else if (!strcmp(val, "codec_consumer")) {
1475 				hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC;
1476 			} else if (!strcmp(val, "codec_master")) {
1477 				SNDERR("deprecated bclk value '%s', use 'codec_provider", val);
1478 
1479 				hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP;
1480 			} else if (!strcmp(val, "codec_provider")) {
1481 				hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP;
1482 			}
1483 			continue;
1484 		}
1485 
1486 		if (strcmp(id, "bclk_freq") == 0 ||
1487 		    strcmp(id, "bclk_rate") == 0) {
1488 			if (parse_unsigned(n, &hw_cfg->bclk_rate))
1489 				return -EINVAL;
1490 			continue;
1491 		}
1492 
1493 		if (strcmp(id, "bclk_invert") == 0 ||
1494 		    strcmp(id, "invert_bclk") == 0) {
1495 			ival = snd_config_get_bool(n);
1496 			if (ival < 0)
1497 				return -EINVAL;
1498 
1499 			hw_cfg->invert_bclk = ival;
1500 			continue;
1501 		}
1502 
1503 		provider_legacy = false;
1504 		if (strcmp(id, "fsync_master") == 0) {
1505 			SNDERR("deprecated option %s, please use 'fsync'\n", id);
1506 			provider_legacy = true;
1507 		}
1508 
1509 		if (provider_legacy ||
1510 		    strcmp(id, "fsync") == 0) {
1511 
1512 			if (snd_config_get_string(n, &val) < 0)
1513 				return -EINVAL;
1514 
1515 			if (!strcmp(val, "master")) {
1516 				/* For backwards capability,
1517 				 * "master" == "codec is slave"
1518 				 */
1519 				SNDERR("deprecated fsync value '%s'", val);
1520 
1521 				hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC;
1522 			} else if (!strcmp(val, "codec_slave")) {
1523 				SNDERR("deprecated fsync value '%s', use 'codec_consumer'", val);
1524 
1525 				hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC;
1526 			} else if (!strcmp(val, "codec_consumer")) {
1527 				hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC;
1528 			} else if (!strcmp(val, "codec_master")) {
1529 				SNDERR("deprecated fsync value '%s', use 'codec_provider'", val);
1530 
1531 				hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CP;
1532 			} else if (!strcmp(val, "codec_provider")) {
1533 				hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CP;
1534 			}
1535 			continue;
1536 		}
1537 
1538 		if (strcmp(id, "fsync_invert") == 0 ||
1539 		    strcmp(id, "invert_fsync") == 0) {
1540 			ival = snd_config_get_bool(n);
1541 			if (ival < 0)
1542 				return -EINVAL;
1543 
1544 			hw_cfg->invert_fsync = ival;
1545 			continue;
1546 		}
1547 
1548 		if (strcmp(id, "fsync_freq") == 0 ||
1549 		    strcmp(id, "fsync_rate") == 0) {
1550 			if (parse_unsigned(n, &hw_cfg->fsync_rate))
1551 				return -EINVAL;
1552 			continue;
1553 		}
1554 
1555 		if (strcmp(id, "mclk_freq") == 0 ||
1556 		    strcmp(id, "mclk_rate") == 0) {
1557 			if (parse_unsigned(n, &hw_cfg->mclk_rate))
1558 				return -EINVAL;
1559 			continue;
1560 		}
1561 
1562 		if (strcmp(id, "mclk") == 0 ||
1563 		    strcmp(id, "mclk_direction") == 0) {
1564 			if (snd_config_get_string(n, &val) < 0)
1565 				return -EINVAL;
1566 
1567 			if (!strcmp(val, "master")) {
1568 				/* For backwards capability,
1569 				 * "master" == "for codec, mclk is input"
1570 				 */
1571 				SNDERR("deprecated mclk value '%s'", val);
1572 
1573 				hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CI;
1574 			} else if (!strcmp(val, "codec_mclk_in")) {
1575 				hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CI;
1576 			} else if (!strcmp(val, "codec_mclk_out")) {
1577 				hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CO;
1578 			}
1579 			continue;
1580 		}
1581 
1582 		if (strcmp(id, "pm_gate_clocks") == 0 ||
1583 		    strcmp(id, "clock_gated") == 0) {
1584 			ival = snd_config_get_bool(n);
1585 			if (ival < 0)
1586 				return -EINVAL;
1587 
1588 			if (ival)
1589 				hw_cfg->clock_gated =
1590 					SND_SOC_TPLG_DAI_CLK_GATE_GATED;
1591 			else
1592 				hw_cfg->clock_gated =
1593 					SND_SOC_TPLG_DAI_CLK_GATE_CONT;
1594 			continue;
1595 		}
1596 
1597 		if (strcmp(id, "tdm_slots") == 0) {
1598 			if (parse_unsigned(n, &hw_cfg->tdm_slots))
1599 				return -EINVAL;
1600 			continue;
1601 		}
1602 
1603 		if (strcmp(id, "tdm_slot_width") == 0) {
1604 			if (parse_unsigned(n, &hw_cfg->tdm_slot_width))
1605 				return -EINVAL;
1606 			continue;
1607 		}
1608 
1609 		if (strcmp(id, "tx_slots") == 0) {
1610 			if (parse_unsigned(n, &hw_cfg->tx_slots))
1611 				return -EINVAL;
1612 			continue;
1613 		}
1614 
1615 		if (strcmp(id, "rx_slots") == 0) {
1616 			if (parse_unsigned(n, &hw_cfg->rx_slots))
1617 				return -EINVAL;
1618 			continue;
1619 		}
1620 
1621 		if (strcmp(id, "tx_channels") == 0) {
1622 			if (parse_unsigned(n, &hw_cfg->tx_channels))
1623 				return -EINVAL;
1624 			continue;
1625 		}
1626 
1627 		if (strcmp(id, "rx_channels") == 0) {
1628 			if (parse_unsigned(n, &hw_cfg->rx_channels))
1629 				return -EINVAL;
1630 			continue;
1631 		}
1632 
1633 	}
1634 
1635 	return 0;
1636 }
1637 
1638 /* save hw config */
tplg_save_hw_config(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1639 int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1640 			struct tplg_elem *elem,
1641 			struct tplg_buf *dst, const char *pfx)
1642 {
1643 	struct snd_soc_tplg_hw_config *hc = elem->hw_cfg;
1644 	int err;
1645 
1646 	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1647 	if (err >= 0 && hc->id)
1648 		err = tplg_save_printf(dst, pfx, "\tid %u\n",
1649 				       hc->id);
1650 	if (err >= 0 && hc->fmt)
1651 		err = tplg_save_printf(dst, pfx, "\tformat '%s'\n",
1652 				       get_audio_hw_format_name(hc->fmt));
1653 	if (err >= 0 && hc->bclk_provider)
1654 		err = tplg_save_printf(dst, pfx, "\tbclk '%s'\n",
1655 				       hc->bclk_provider == SND_SOC_TPLG_BCLK_CC ?
1656 						"codec_consumer" : "codec_provider");
1657 	if (err >= 0 && hc->bclk_rate)
1658 		err = tplg_save_printf(dst, pfx, "\tbclk_freq %u\n",
1659 				       hc->bclk_rate);
1660 	if (err >= 0 && hc->invert_bclk)
1661 		err = tplg_save_printf(dst, pfx, "\tbclk_invert 1\n");
1662 	if (err >= 0 && hc->fsync_provider)
1663 		err = tplg_save_printf(dst, pfx, "\tfsync_provider '%s'\n",
1664 				       hc->fsync_provider == SND_SOC_TPLG_FSYNC_CC ?
1665 						"codec_consumer" : "codec_provider");
1666 	if (err >= 0 && hc->fsync_rate)
1667 		err = tplg_save_printf(dst, pfx, "\tfsync_freq %u\n",
1668 				       hc->fsync_rate);
1669 	if (err >= 0 && hc->invert_fsync)
1670 		err = tplg_save_printf(dst, pfx, "\tfsync_invert 1\n");
1671 	if (err >= 0 && hc->mclk_rate)
1672 		err = tplg_save_printf(dst, pfx, "\tmclk_freq %u\n",
1673 				       hc->mclk_rate);
1674 	if (err >= 0 && hc->mclk_direction)
1675 		err = tplg_save_printf(dst, pfx, "\tmclk '%s'\n",
1676 				       hc->mclk_direction == SND_SOC_TPLG_MCLK_CI ?
1677 						"codec_mclk_in" : "codec_mclk_out");
1678 	if (err >= 0 && hc->clock_gated)
1679 		err = tplg_save_printf(dst, pfx, "\tpm_gate_clocks 1\n");
1680 	if (err >= 0 && hc->tdm_slots)
1681 		err = tplg_save_printf(dst, pfx, "\ttdm_slots %u\n",
1682 				       hc->tdm_slots);
1683 	if (err >= 0 && hc->tdm_slot_width)
1684 		err = tplg_save_printf(dst, pfx, "\ttdm_slot_width %u\n",
1685 				       hc->tdm_slot_width);
1686 	if (err >= 0 && hc->tx_slots)
1687 		err = tplg_save_printf(dst, pfx, "\ttx_slots %u\n",
1688 				       hc->tx_slots);
1689 	if (err >= 0 && hc->rx_slots)
1690 		err = tplg_save_printf(dst, pfx, "\trx_slots %u\n",
1691 				       hc->rx_slots);
1692 	if (err >= 0 && hc->tx_channels)
1693 		err = tplg_save_printf(dst, pfx, "\ttx_channels %u\n",
1694 				       hc->tx_channels);
1695 	if (err >= 0 && hc->rx_channels)
1696 		err = tplg_save_printf(dst, pfx, "\trx_channels %u\n",
1697 				       hc->rx_channels);
1698 	if (err >= 0)
1699 		err = tplg_save_printf(dst, pfx, "}\n");
1700 	return err;
1701 }
1702 
1703 /* copy stream object */
tplg_add_stream_object(struct snd_soc_tplg_stream * strm,struct snd_tplg_stream_template * strm_tpl)1704 static void tplg_add_stream_object(struct snd_soc_tplg_stream *strm,
1705 				   struct snd_tplg_stream_template *strm_tpl)
1706 {
1707 	snd_strlcpy(strm->name, strm_tpl->name,
1708 		SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1709 	strm->format = strm_tpl->format;
1710 	strm->rate = strm_tpl->rate;
1711 	strm->period_bytes = strm_tpl->period_bytes;
1712 	strm->buffer_bytes = strm_tpl->buffer_bytes;
1713 	strm->channels = strm_tpl->channels;
1714 }
1715 
tplg_add_stream_caps(snd_tplg_t * tplg,struct snd_tplg_stream_caps_template * caps_tpl)1716 static int tplg_add_stream_caps(snd_tplg_t *tplg,
1717 				struct snd_tplg_stream_caps_template *caps_tpl)
1718 {
1719 	struct snd_soc_tplg_stream_caps *caps;
1720 	struct tplg_elem *elem;
1721 
1722 	elem = tplg_elem_new_common(tplg, NULL, caps_tpl->name,
1723 				    SND_TPLG_TYPE_STREAM_CAPS);
1724 	if (!elem)
1725 		return -ENOMEM;
1726 
1727 	caps = elem->stream_caps;
1728 
1729 	snd_strlcpy(caps->name, caps_tpl->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1730 
1731 	caps->formats = caps_tpl->formats;
1732 	caps->rates = caps_tpl->rates;
1733 	caps->rate_min = caps_tpl->rate_min;
1734 	caps->rate_max = caps_tpl->rate_max;
1735 	caps->channels_min = caps_tpl->channels_min;
1736 	caps->channels_max = caps_tpl->channels_max;
1737 	caps->periods_min = caps_tpl->periods_min;
1738 	caps->periods_max = caps_tpl->periods_max;
1739 	caps->period_size_min = caps_tpl->period_size_min;
1740 	caps->period_size_max = caps_tpl->period_size_max;
1741 	caps->buffer_size_min = caps_tpl->buffer_size_min;
1742 	caps->buffer_size_max = caps_tpl->buffer_size_max;
1743 	caps->sig_bits = caps_tpl->sig_bits;
1744 	return 0;
1745 }
1746 
1747 /* Add a PCM element (FE DAI & DAI link) from C API */
tplg_add_pcm_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)1748 int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1749 {
1750 	struct snd_tplg_pcm_template *pcm_tpl = t->pcm;
1751 	struct snd_soc_tplg_private *priv;
1752 	struct snd_soc_tplg_pcm *pcm;
1753 	struct tplg_elem *elem;
1754 	int ret, i;
1755 
1756 	tplg_dbg("PCM: %s, DAI %s", pcm_tpl->pcm_name, pcm_tpl->dai_name);
1757 
1758 	if (pcm_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX)
1759 		return -EINVAL;
1760 
1761 	elem = tplg_elem_new_common(tplg, NULL, pcm_tpl->pcm_name,
1762 		SND_TPLG_TYPE_PCM);
1763 	if (!elem)
1764 		return -ENOMEM;
1765 
1766 	pcm = elem->pcm;
1767 	pcm->size = elem->size;
1768 
1769 	snd_strlcpy(pcm->pcm_name, pcm_tpl->pcm_name,
1770 		SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1771 	snd_strlcpy(pcm->dai_name, pcm_tpl->dai_name,
1772 		SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1773 	pcm->pcm_id = pcm_tpl->pcm_id;
1774 	pcm->dai_id = pcm_tpl->dai_id;
1775 	pcm->playback = pcm_tpl->playback;
1776 	pcm->capture = pcm_tpl->capture;
1777 	pcm->compress = pcm_tpl->compress;
1778 
1779 	for (i = 0; i < 2; i++) {
1780 		if (!pcm_tpl->caps[i] || !pcm_tpl->caps[i]->name)
1781 			continue;
1782 		ret = tplg_add_stream_caps(tplg, pcm_tpl->caps[i]);
1783 		if (ret < 0)
1784 			return ret;
1785 		snd_strlcpy(pcm->caps[i].name, pcm_tpl->caps[i]->name,
1786 			    sizeof(pcm->caps[i].name));
1787 	}
1788 
1789 	pcm->flag_mask = pcm_tpl->flag_mask;
1790 	pcm->flags = pcm_tpl->flags;
1791 
1792 	pcm->num_streams = pcm_tpl->num_streams;
1793 	for (i = 0; i < pcm_tpl->num_streams; i++)
1794 		tplg_add_stream_object(&pcm->stream[i], &pcm_tpl->stream[i]);
1795 
1796 	/* private data */
1797 	priv = pcm_tpl->priv;
1798 	if (priv && priv->size > 0) {
1799 		ret = tplg_add_data(tplg, elem, priv,
1800 				    sizeof(*priv) + priv->size);
1801 		if (ret < 0)
1802 			return ret;
1803 	}
1804 
1805 	return 0;
1806 }
1807 
1808 /* Set link HW config from C API template */
set_link_hw_config(struct snd_soc_tplg_hw_config * cfg,struct snd_tplg_hw_config_template * tpl)1809 static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg,
1810 			      struct snd_tplg_hw_config_template *tpl)
1811 {
1812 	unsigned int i;
1813 
1814 	cfg->size = sizeof(*cfg);
1815 	cfg->id = tpl->id;
1816 
1817 	cfg->fmt = tpl->fmt;
1818 	cfg->clock_gated = tpl->clock_gated;
1819 	cfg->invert_bclk = tpl->invert_bclk;
1820 	cfg->invert_fsync = tpl->invert_fsync;
1821 	cfg->bclk_provider = tpl->bclk_provider;
1822 	cfg->fsync_provider = tpl->fsync_provider;
1823 	cfg->mclk_direction = tpl->mclk_direction;
1824 	cfg->reserved = tpl->reserved;
1825 	cfg->mclk_rate = tpl->mclk_rate;
1826 	cfg->bclk_rate = tpl->bclk_rate;
1827 	cfg->fsync_rate = tpl->fsync_rate;
1828 
1829 	cfg->tdm_slots = tpl->tdm_slots;
1830 	cfg->tdm_slot_width = tpl->tdm_slot_width;
1831 	cfg->tx_slots = tpl->tx_slots;
1832 	cfg->rx_slots = tpl->rx_slots;
1833 
1834 	if (cfg->tx_channels > SND_SOC_TPLG_MAX_CHAN
1835 		|| cfg->rx_channels > SND_SOC_TPLG_MAX_CHAN)
1836 		return -EINVAL;
1837 
1838 	cfg->tx_channels = tpl->tx_channels;
1839 	for (i = 0; i < cfg->tx_channels; i++)
1840 		cfg->tx_chanmap[i] = tpl->tx_chanmap[i];
1841 
1842 	cfg->rx_channels = tpl->rx_channels;
1843 	for (i = 0; i < cfg->rx_channels; i++)
1844 		cfg->rx_chanmap[i] = tpl->rx_chanmap[i];
1845 
1846 	return 0;
1847 }
1848 
1849 /* Add a physical DAI link element from C API */
tplg_add_link_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)1850 int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1851 {
1852 	struct snd_tplg_link_template *link_tpl = t->link;
1853 	struct snd_soc_tplg_link_config *link;
1854 	struct snd_soc_tplg_private *priv;
1855 	struct tplg_elem *elem;
1856 	unsigned int i;
1857 	int ret;
1858 
1859 	if (t->type != SND_TPLG_TYPE_LINK && t->type != SND_TPLG_TYPE_BE
1860 	    && t->type != SND_TPLG_TYPE_CC)
1861 		return -EINVAL;
1862 
1863 	elem = tplg_elem_new_common(tplg, NULL, link_tpl->name, t->type);
1864 	if (!elem)
1865 		return -ENOMEM;
1866 
1867 	tplg_dbg("Link: %s", link_tpl->name);
1868 
1869 	link = elem->link;
1870 	link->size = elem->size;
1871 
1872 	/* ID and names */
1873 	link->id = link_tpl->id;
1874 	snd_strlcpy(link->name, link_tpl->name,
1875 		       SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1876 	snd_strlcpy(link->stream_name, link_tpl->stream_name,
1877 		       SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1878 
1879 	/* stream configs */
1880 	if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX)
1881 		return -EINVAL;
1882 	link->num_streams = link_tpl->num_streams;
1883 	for (i = 0; i < link->num_streams; i++)
1884 		tplg_add_stream_object(&link->stream[i], &link_tpl->stream[i]);
1885 
1886 	/* HW configs */
1887 	if (link_tpl->num_hw_configs > SND_SOC_TPLG_HW_CONFIG_MAX)
1888 		return -EINVAL;
1889 	link->num_hw_configs = link_tpl->num_hw_configs;
1890 	link->default_hw_config_id = link_tpl->default_hw_config_id;
1891 	for (i = 0; i < link->num_hw_configs; i++)
1892 		set_link_hw_config(&link->hw_config[i], &link_tpl->hw_config[i]);
1893 
1894 	/* flags */
1895 	link->flag_mask = link_tpl->flag_mask;
1896 	link->flags = link_tpl->flags;
1897 
1898 	/* private data */
1899 	priv = link_tpl->priv;
1900 	if (priv && priv->size > 0) {
1901 		ret = tplg_add_data(tplg, elem, priv,
1902 				    sizeof(*priv) + priv->size);
1903 		if (ret < 0)
1904 			return ret;
1905 	}
1906 
1907 	return 0;
1908 }
1909 
tplg_add_dai_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)1910 int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
1911 {
1912 	struct snd_tplg_dai_template *dai_tpl = t->dai;
1913 	struct snd_soc_tplg_dai *dai;
1914 	struct snd_soc_tplg_private *priv;
1915 	struct tplg_elem *elem;
1916 	int ret, i;
1917 
1918 	tplg_dbg("DAI %s", dai_tpl->dai_name);
1919 
1920 	elem = tplg_elem_new_common(tplg, NULL, dai_tpl->dai_name,
1921 				    SND_TPLG_TYPE_DAI);
1922 	if (!elem)
1923 		return -ENOMEM;
1924 
1925 	dai = elem->dai;
1926 	dai->size = elem->size;
1927 
1928 	snd_strlcpy(dai->dai_name, dai_tpl->dai_name,
1929 		SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1930 	dai->dai_id = dai_tpl->dai_id;
1931 
1932 	/* stream caps */
1933 	dai->playback = dai_tpl->playback;
1934 	dai->capture = dai_tpl->capture;
1935 
1936 	for (i = 0; i < 2; i++) {
1937 		if (!dai_tpl->caps[i] || !dai_tpl->caps[i]->name)
1938 			continue;
1939 		ret = tplg_add_stream_caps(tplg, dai_tpl->caps[i]);
1940 		if (ret < 0)
1941 			return ret;
1942 		snd_strlcpy(dai->caps[i].name, dai_tpl->caps[i]->name,
1943 			    sizeof(dai->caps[i].name));
1944 	}
1945 
1946 	/* flags */
1947 	dai->flag_mask = dai_tpl->flag_mask;
1948 	dai->flags = dai_tpl->flags;
1949 
1950 	/* private data */
1951 	priv = dai_tpl->priv;
1952 	if (priv && priv->size > 0) {
1953 		ret = tplg_add_data(tplg, elem, priv,
1954 				    sizeof(*priv) + priv->size);
1955 		if (ret < 0)
1956 			return ret;
1957 	}
1958 
1959 	return 0;
1960 }
1961 
1962 /* decode pcm from the binary input */
tplg_decode_pcm(snd_tplg_t * tplg,size_t pos,struct snd_soc_tplg_hdr * hdr,void * bin,size_t size)1963 int tplg_decode_pcm(snd_tplg_t *tplg,
1964 		    size_t pos,
1965 		    struct snd_soc_tplg_hdr *hdr,
1966 		    void *bin, size_t size)
1967 {
1968 	struct snd_soc_tplg_pcm *pcm;
1969 	snd_tplg_obj_template_t t;
1970 	struct snd_tplg_pcm_template *pt;
1971 	struct snd_tplg_stream_caps_template caps[2], *cap;
1972 	struct snd_tplg_stream_template *stream;
1973 	unsigned int i;
1974 	size_t asize;
1975 	int err;
1976 
1977 	err = tplg_decode_template(tplg, pos, hdr, &t);
1978 	if (err < 0)
1979 		return err;
1980 
1981 	asize = sizeof(*pt) + SND_SOC_TPLG_STREAM_CONFIG_MAX * sizeof(*stream);
1982 	pt = alloca(asize);
1983 
1984 next:
1985 	memset(pt, 0, asize);
1986 	pcm = bin;
1987 
1988 	if (size < sizeof(*pcm)) {
1989 		SNDERR("pcm: small size %d", size);
1990 		return -EINVAL;
1991 	}
1992 	if (sizeof(*pcm) != pcm->size) {
1993 		SNDERR("pcm: unknown element size %d (expected %zd)",
1994 		       pcm->size, sizeof(*pcm));
1995 		return -EINVAL;
1996 	}
1997 	if (pcm->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) {
1998 		SNDERR("pcm: wrong number of streams %d", pcm->num_streams);
1999 		return -EINVAL;
2000 	}
2001 	if (sizeof(*pcm) + pcm->priv.size > size) {
2002 		SNDERR("pcm: wrong private data size %d", pcm->priv.size);
2003 		return -EINVAL;
2004 	}
2005 
2006 	tplg_log(tplg, 'D', pos, "pcm: size %d private size %d streams %d",
2007 		 pcm->size, pcm->priv.size, pcm->num_streams);
2008 
2009 	pt->pcm_name = pcm->pcm_name;
2010 	tplg_log(tplg, 'D', pos, "pcm: pcm_name '%s'", pt->pcm_name);
2011 	pt->dai_name = pcm->dai_name;
2012 	tplg_log(tplg, 'D', pos, "pcm: dai_name '%s'", pt->dai_name);
2013 	pt->pcm_id = pcm->pcm_id;
2014 	pt->dai_id = pcm->dai_id;
2015 	tplg_log(tplg, 'D', pos, "pcm: pcm_id %d dai_id %d", pt->pcm_id, pt->dai_id);
2016 	pt->playback = pcm->playback;
2017 	pt->capture = pcm->capture;
2018 	pt->compress = pcm->compress;
2019 	tplg_log(tplg, 'D', pos, "pcm: playback %d capture %d compress %d",
2020 		 pt->playback, pt->capture, pt->compress);
2021 	pt->num_streams = pcm->num_streams;
2022 	pt->flag_mask = pcm->flag_mask;
2023 	pt->flags = pcm->flags;
2024 	for (i = 0; i < pcm->num_streams; i++) {
2025 		stream = &pt->stream[i];
2026 		if (pcm->stream[i].size != sizeof(pcm->stream[0])) {
2027 			SNDERR("pcm: unknown stream structure size %d",
2028 			       pcm->stream[i].size);
2029 			return -EINVAL;
2030 		}
2031 		stream->name = pcm->stream[i].name;
2032 		tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, stream[i]),
2033 			 "stream %d: '%s'", i, stream->name);
2034 		stream->format = pcm->stream[i].format;
2035 		stream->rate = pcm->stream[i].rate;
2036 		stream->period_bytes = pcm->stream[i].period_bytes;
2037 		stream->buffer_bytes = pcm->stream[i].buffer_bytes;
2038 		stream->channels = pcm->stream[i].channels;
2039 	}
2040 	for (i = 0; i < 2; i++) {
2041 		if (i == 0 && !pcm->playback)
2042 			continue;
2043 		if (i == 1 && !pcm->capture)
2044 			continue;
2045 		cap = &caps[i];
2046 		pt->caps[i] = cap;
2047 		if (pcm->caps[i].size != sizeof(pcm->caps[0])) {
2048 			SNDERR("pcm: unknown caps structure size %d",
2049 			       pcm->caps[i].size);
2050 			return -EINVAL;
2051 		}
2052 		cap->name = pcm->caps[i].name;
2053 		tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, caps[i]),
2054 			 "caps %d: '%s'", i, cap->name);
2055 		cap->formats = pcm->caps[i].formats;
2056 		cap->rates = pcm->caps[i].rates;
2057 		cap->rate_min = pcm->caps[i].rate_min;
2058 		cap->rate_max = pcm->caps[i].rate_max;
2059 		cap->channels_min = pcm->caps[i].channels_min;
2060 		cap->channels_max = pcm->caps[i].channels_max;
2061 		cap->periods_min = pcm->caps[i].periods_min;
2062 		cap->periods_max = pcm->caps[i].periods_max;
2063 		cap->period_size_min = pcm->caps[i].period_size_min;
2064 		cap->period_size_max = pcm->caps[i].period_size_max;
2065 		cap->buffer_size_min = pcm->caps[i].buffer_size_min;
2066 		cap->buffer_size_max = pcm->caps[i].buffer_size_max;
2067 		cap->sig_bits = pcm->caps[i].sig_bits;
2068 	}
2069 
2070 	tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, priv),
2071 		 "pcm: private start");
2072 	pt->priv = &pcm->priv;
2073 
2074 	bin += sizeof(*pcm) + pcm->priv.size;
2075 	size -= sizeof(*pcm) + pcm->priv.size;
2076 	pos += sizeof(*pcm) + pcm->priv.size;
2077 
2078 	t.pcm = pt;
2079 	err = snd_tplg_add_object(tplg, &t);
2080 	if (err < 0)
2081 		return err;
2082 
2083 	if (size > 0)
2084 		goto next;
2085 
2086 	return 0;
2087 }
2088 
2089 /* decode dai from the binary input */
tplg_decode_dai(snd_tplg_t * tplg ATTRIBUTE_UNUSED,size_t pos ATTRIBUTE_UNUSED,struct snd_soc_tplg_hdr * hdr ATTRIBUTE_UNUSED,void * bin ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)2090 int tplg_decode_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
2091 		    size_t pos ATTRIBUTE_UNUSED,
2092 		    struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
2093 		    void *bin ATTRIBUTE_UNUSED,
2094 		    size_t size ATTRIBUTE_UNUSED)
2095 {
2096 	SNDERR("not implemented");
2097 	return -ENXIO;
2098 }
2099 
2100 /* decode cc from the binary input */
tplg_decode_cc(snd_tplg_t * tplg ATTRIBUTE_UNUSED,size_t pos ATTRIBUTE_UNUSED,struct snd_soc_tplg_hdr * hdr ATTRIBUTE_UNUSED,void * bin ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)2101 int tplg_decode_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
2102 		   size_t pos ATTRIBUTE_UNUSED,
2103 		   struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
2104 		   void *bin ATTRIBUTE_UNUSED,
2105 		   size_t size ATTRIBUTE_UNUSED)
2106 {
2107 	SNDERR("not implemented");
2108 	return -ENXIO;
2109 }
2110 
2111 /* decode link from the binary input */
tplg_decode_link(snd_tplg_t * tplg,size_t pos,struct snd_soc_tplg_hdr * hdr,void * bin,size_t size)2112 int tplg_decode_link(snd_tplg_t *tplg,
2113 		     size_t pos,
2114 		     struct snd_soc_tplg_hdr *hdr,
2115 		     void *bin, size_t size)
2116 {
2117 	struct snd_soc_tplg_link_config *link;
2118 	snd_tplg_obj_template_t t;
2119 	struct snd_tplg_link_template lt;
2120 	struct snd_tplg_stream_template streams[SND_SOC_TPLG_STREAM_CONFIG_MAX];
2121 	struct snd_tplg_stream_template *stream;
2122 	struct snd_tplg_hw_config_template hws[SND_SOC_TPLG_HW_CONFIG_MAX];
2123 	struct snd_tplg_hw_config_template *hw;
2124 	unsigned int i, j;
2125 	int err;
2126 
2127 	err = tplg_decode_template(tplg, pos, hdr, &t);
2128 	if (err < 0)
2129 		return err;
2130 
2131 next:
2132 	memset(&lt, 0, sizeof(lt));
2133 	memset(streams, 0, sizeof(streams));
2134 	memset(hws, 0, sizeof(hws));
2135 	link = bin;
2136 
2137 	if (size < sizeof(*link)) {
2138 		SNDERR("link: small size %d", size);
2139 		return -EINVAL;
2140 	}
2141 	if (sizeof(*link) != link->size) {
2142 		SNDERR("link: unknown element size %d (expected %zd)",
2143 		       link->size, sizeof(*link));
2144 		return -EINVAL;
2145 	}
2146 	if (link->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) {
2147 		SNDERR("link: wrong number of streams %d", link->num_streams);
2148 		return -EINVAL;
2149 	}
2150 	if (link->num_hw_configs > SND_SOC_TPLG_HW_CONFIG_MAX) {
2151 		SNDERR("link: wrong number of streams %d", link->num_streams);
2152 		return -EINVAL;
2153 	}
2154 	if (sizeof(*link) + link->priv.size > size) {
2155 		SNDERR("link: wrong private data size %d", link->priv.size);
2156 		return -EINVAL;
2157 	}
2158 
2159 	tplg_log(tplg, 'D', pos, "link: size %d private size %d streams %d "
2160 		 "hw_configs %d",
2161 		 link->size, link->priv.size, link->num_streams,
2162 		 link->num_hw_configs);
2163 
2164 	lt.id = link->id;
2165 	lt.name = link->name;
2166 	tplg_log(tplg, 'D', pos, "link: name '%s'", lt.name);
2167 	lt.stream_name = link->stream_name;
2168 	tplg_log(tplg, 'D', pos, "link: stream_name '%s'", lt.stream_name);
2169 	lt.num_streams = link->num_streams;
2170 	lt.num_hw_configs = link->num_hw_configs;
2171 	lt.default_hw_config_id = link->default_hw_config_id;
2172 	lt.flag_mask = link->flag_mask;
2173 	lt.flags = link->flags;
2174 	for (i = 0; i < link->num_streams; i++) {
2175 		stream = &streams[i];
2176 		if (link->stream[i].size != sizeof(link->stream[0])) {
2177 			SNDERR("link: unknown stream structure size %d",
2178 			       link->stream[i].size);
2179 			return -EINVAL;
2180 		}
2181 		stream->name = link->stream[i].name;
2182 		tplg_log(tplg, 'D',
2183 			 pos + offsetof(struct snd_soc_tplg_link_config, stream[i]),
2184 			 "stream %d: '%s'", i, stream->name);
2185 		stream->format = link->stream[i].format;
2186 		stream->rate = link->stream[i].rate;
2187 		stream->period_bytes = link->stream[i].period_bytes;
2188 		stream->buffer_bytes = link->stream[i].buffer_bytes;
2189 		stream->channels = link->stream[i].channels;
2190 	}
2191 	lt.stream = streams;
2192 	for (i = 0; i < link->num_hw_configs; i++) {
2193 		hw = &hws[i];
2194 		if (link->hw_config[i].size != sizeof(link->hw_config[0])) {
2195 			SNDERR("link: unknown hw_config structure size %d",
2196 			       link->hw_config[i].size);
2197 			return -EINVAL;
2198 		}
2199 		hw->id = link->hw_config[i].id;
2200 		hw->fmt = link->hw_config[i].fmt;
2201 		hw->clock_gated = link->hw_config[i].clock_gated;
2202 		hw->invert_bclk = link->hw_config[i].invert_bclk;
2203 		hw->invert_fsync = link->hw_config[i].invert_fsync;
2204 		hw->bclk_provider = link->hw_config[i].bclk_provider;
2205 		hw->fsync_provider = link->hw_config[i].fsync_provider;
2206 		hw->mclk_direction = link->hw_config[i].mclk_direction;
2207 		hw->mclk_rate = link->hw_config[i].mclk_rate;
2208 		hw->bclk_rate = link->hw_config[i].bclk_rate;
2209 		hw->fsync_rate = link->hw_config[i].fsync_rate;
2210 		hw->tdm_slots = link->hw_config[i].tdm_slots;
2211 		hw->tdm_slot_width = link->hw_config[i].tdm_slot_width;
2212 		hw->tx_slots = link->hw_config[i].tx_slots;
2213 		hw->rx_slots = link->hw_config[i].rx_slots;
2214 		hw->tx_channels = link->hw_config[i].tx_channels;
2215 		if (hw->tx_channels > SND_SOC_TPLG_MAX_CHAN) {
2216 			SNDERR("link: wrong tx channels %d", hw->tx_channels);
2217 			return -EINVAL;
2218 		}
2219 		for (j = 0; j < hw->tx_channels; j++)
2220 			hw->tx_chanmap[j] = link->hw_config[i].tx_chanmap[j];
2221 		hw->rx_channels = link->hw_config[i].rx_channels;
2222 		if (hw->rx_channels > SND_SOC_TPLG_MAX_CHAN) {
2223 			SNDERR("link: wrong rx channels %d", hw->tx_channels);
2224 			return -EINVAL;
2225 		}
2226 		for (j = 0; j < hw->rx_channels; j++)
2227 			hw->rx_chanmap[j] = link->hw_config[i].rx_chanmap[j];
2228 	}
2229 	lt.hw_config = hws;
2230 
2231 	tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_pcm, priv),
2232 		 "link: private start");
2233 	lt.priv = &link->priv;
2234 
2235 	bin += sizeof(*link) + link->priv.size;
2236 	size -= sizeof(*link) + link->priv.size;
2237 	pos += sizeof(*link) + link->priv.size;
2238 
2239 	t.link = &lt;
2240 	err = snd_tplg_add_object(tplg, &t);
2241 	if (err < 0)
2242 		return err;
2243 
2244 	if (size > 0)
2245 		goto next;
2246 
2247 	return 0;
2248 }
2249