blob: 831c5cffe9c2d4200bfdeb0634eb9a517fe9f269 [file] [log] [blame]
Ranjani Sridharan46704022018-05-31 19:29:05 -07001/*
2 * Copyright (c) 2018, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Intel Corporation nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
29 * Liam Girdwood <liam.r.girdwood@linux.intel.com>
30 */
31
32/*
33 * Topology parser to parse topology bin file
34 * and set up components and pipeline
35 */
36
37#include <sof/ipc.h>
38#include <stdio.h>
39#include <string.h>
40#include <dlfcn.h>
41#include <sof/audio/component.h>
42#include "host/topology.h"
43#include "host/file.h"
44
Ranjani Sridharan46704022018-05-31 19:29:05 -070045FILE *file;
46char pipeline_string[DEBUG_MSG_LEN];
Ranjani Sridharan03067c62018-06-27 15:09:25 -070047struct shared_lib_table *lib_table;
Ranjani Sridharan46704022018-05-31 19:29:05 -070048
49/*
50 * Register component driver
51 * Only needed once per component type
52 */
53static void register_comp(int comp_type)
54{
Ranjani Sridharan03067c62018-06-27 15:09:25 -070055 int index;
56 char message[DEBUG_MSG_LEN];
Ranjani Sridharan46704022018-05-31 19:29:05 -070057
Ranjani Sridharan03067c62018-06-27 15:09:25 -070058 /* register file comp driver (no shared library needed) */
59 if (comp_type == SND_SOC_TPLG_DAPM_DAI_IN ||
60 comp_type == SND_SOC_TPLG_DAPM_AIF_IN) {
61 if (!lib_table[0].register_drv) {
Ranjani Sridharan46704022018-05-31 19:29:05 -070062 sys_comp_file_init();
Ranjani Sridharan03067c62018-06-27 15:09:25 -070063 lib_table[0].register_drv = 1;
64 debug_print("registered file comp driver\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -070065 }
Ranjani Sridharan03067c62018-06-27 15:09:25 -070066 return;
Ranjani Sridharan46704022018-05-31 19:29:05 -070067 }
Ranjani Sridharan03067c62018-06-27 15:09:25 -070068
69 /* get index of comp in shared library table */
70 index = get_index_by_type(comp_type, lib_table);
71 if (index < 0)
72 return;
73
74 /* register comp driver if not already registered */
75 if (!lib_table[index].register_drv) {
76 sprintf(message, "registered comp driver for %s\n",
77 lib_table[index].comp_name);
78 debug_print(message);
79
80 /* register comp driver */
81 void (*comp_init)() =
82 (void (*)(void))dlsym(lib_table[index].handle,
83 lib_table[index].comp_init);
84 comp_init();
85 lib_table[index].register_drv = 1;
86 }
87
Ranjani Sridharan46704022018-05-31 19:29:05 -070088}
89
90/* read vendor tuples array from topology */
91static int read_array(struct snd_soc_tplg_vendor_array *array)
92{
93 struct snd_soc_tplg_vendor_uuid_elem uuid;
94 struct snd_soc_tplg_vendor_string_elem string;
95 struct snd_soc_tplg_vendor_value_elem value;
96 int j, ret = 0;
97 size_t size;
98
99 switch (array->type) {
100 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
101
102 /* copy uuid elems into array */
103 for (j = 0; j < array->num_elems; j++) {
104 size = sizeof(struct snd_soc_tplg_vendor_uuid_elem);
105 ret = fread(&uuid, size, 1, file);
106 if (ret != 1)
107 return -EINVAL;
108 memcpy(&array->uuid[j], &uuid, size);
109 }
110 break;
111 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
112
113 /* copy string elems into array */
114 for (j = 0; j < array->num_elems; j++) {
115 size = sizeof(struct snd_soc_tplg_vendor_string_elem);
116 ret = fread(&string, size, 1, file);
117 if (ret != 1)
118 return -EINVAL;
119 memcpy(&array->string[j], &string, size);
120 }
121 break;
122 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
123 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
124 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
125 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
126 /* copy value elems into array */
127 for (j = 0; j < array->num_elems; j++) {
128 size = sizeof(struct snd_soc_tplg_vendor_value_elem);
129 ret = fread(&value, size, 1, file);
130 if (ret != 1)
131 return -EINVAL;
132 memcpy(&array->value[j], &value, size);
133 }
134 break;
135 default:
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700136 fprintf(stderr, "error: unknown token type %d\n", array->type);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700137 return -EINVAL;
138 }
139 return 0;
140}
141
142/* load pipeline graph DAPM widget*/
143static int load_graph(struct sof *sof, struct comp_info *temp_comp_list,
144 int count, int num_comps, int pipeline_id)
145{
146 struct sof_ipc_pipe_comp_connect connection;
147 struct snd_soc_tplg_dapm_graph_elem *graph_elem;
148 size_t size;
149 int i, j, ret = 0;
150
151 /* allocate memory for graph elem */
152 size = sizeof(struct snd_soc_tplg_dapm_graph_elem);
153 graph_elem = (struct snd_soc_tplg_dapm_graph_elem *)malloc(size);
154 if (!graph_elem) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700155 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700156 return -EINVAL;
157 }
158
159 /* set up component connections */
160 connection.source_id = -1;
161 connection.sink_id = -1;
162 for (i = 0; i < count; i++) {
163 size = sizeof(struct snd_soc_tplg_dapm_graph_elem);
164 ret = fread(graph_elem, size, 1, file);
165 if (ret != 1)
166 return -EINVAL;
167
168 /* look up component id from the component list */
169 for (j = 0; j < num_comps; j++) {
170 if (strcmp(temp_comp_list[j].name,
171 graph_elem->source) == 0)
172 connection.source_id = temp_comp_list[j].id;
173
174 if (strcmp(temp_comp_list[j].name,
175 graph_elem->sink) == 0)
176 connection.sink_id = temp_comp_list[j].id;
177 }
178
179 strcat(pipeline_string, graph_elem->source);
180 strcat(pipeline_string, "->");
181
182 if (i == (count - 1))
183 strcat(pipeline_string, graph_elem->sink);
184
185 /* connect source and sink */
186 if (connection.source_id != -1 && connection.sink_id != -1)
187 if (ipc_comp_connect(sof->ipc, &connection) < 0) {
188 fprintf(stderr, "error: comp connect\n");
189 return -EINVAL;
190 }
191 }
192
193 /* pipeline complete after pipeline connections are established */
194 for (i = 0; i < num_comps; i++) {
195 if (temp_comp_list[i].pipeline_id == pipeline_id &&
196 temp_comp_list[i].type == SND_SOC_TPLG_DAPM_SCHEDULER)
197 ipc_pipeline_complete(sof->ipc, temp_comp_list[i].id);
198 }
199
200 free(graph_elem);
201 return 0;
202}
203
204/* load buffer DAPM widget */
205static int load_buffer(struct sof *sof, int comp_id, int pipeline_id, int size)
206{
207 struct sof_ipc_buffer buffer;
208 struct snd_soc_tplg_vendor_array *array = NULL;
209 int ret = 0;
210
211 /* configure buffer */
212 buffer.comp.id = comp_id;
213 buffer.comp.pipeline_id = pipeline_id;
214
215 /* allocate memory for vendor tuple array */
216 array = (struct snd_soc_tplg_vendor_array *)malloc(size);
217 ret = fread(array, sizeof(struct snd_soc_tplg_vendor_array), 1, file);
218 if (ret != 1)
219 return -EINVAL;
220
221 read_array(array);
222 /* parse buffer tokens */
223 ret = sof_parse_tokens(&buffer, buffer_tokens,
224 ARRAY_SIZE(buffer_tokens), array,
225 size);
226
227 /* create buffer component */
228 if (ipc_buffer_new(sof->ipc, &buffer) < 0) {
229 fprintf(stderr, "error: buffer new\n");
230 return -EINVAL;
231 }
232 free(array);
233 return 0;
234}
235
236/* load fileread component */
237static int load_fileread(struct sof *sof, int comp_id, int pipeline_id,
238 int size, char *bits_in, int *fr_id, int *sched_id)
239{
240 struct sof_ipc_comp_file fileread;
241 struct snd_soc_tplg_vendor_array *array = NULL;
242 size_t total_array_size = 0, read_size;
243 int ret = 0;
244
245 fileread.config.frame_fmt = find_format(bits_in);
246
247 /* allocate memory for vendor tuple array */
248 array = (struct snd_soc_tplg_vendor_array *)malloc(size);
249 if (!array) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700250 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700251 return -EINVAL;
252 }
253
254 /* read vendor tokens */
255 while (total_array_size < size) {
256 read_size = sizeof(struct snd_soc_tplg_vendor_array);
257 ret = fread(array, read_size, 1, file);
258 if (ret != 1)
259 return -EINVAL;
260 read_array(array);
261
262 /* parse comp tokens */
263 ret = sof_parse_tokens(&fileread.config, comp_tokens,
264 ARRAY_SIZE(comp_tokens), array,
265 array->size);
266 if (ret != 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700267 fprintf(stderr, "error: parse fileread tokens %d\n",
268 size);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700269 return -EINVAL;
270 }
271 total_array_size += array->size;
272 }
273
274 /* configure fileread */
275 fileread.fn = strdup(input_file);
276 fileread.mode = FILE_READ;
277 fileread.comp.id = comp_id;
278
279 /* use fileread comp as scheduling comp */
280 *fr_id = *sched_id = comp_id;
281 fileread.comp.hdr.size = sizeof(struct sof_ipc_comp_file);
282 fileread.comp.type = SOF_COMP_FILEREAD;
283 fileread.comp.pipeline_id = pipeline_id;
284
285 /* create fileread component */
286 if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&fileread) < 0) {
287 fprintf(stderr, "error: comp register\n");
288 return -EINVAL;
289 }
290
291 free(array);
292 free(fileread.fn);
293 return 0;
294}
295
296/* load filewrite component */
297static int load_filewrite(struct sof *sof, int comp_id, int pipeline_id,
298 int size, int *fw_id)
299{
300 struct sof_ipc_comp_file filewrite;
301 struct snd_soc_tplg_vendor_array *array = NULL;
302 size_t total_array_size = 0, read_size;
303 int ret = 0;
304
305 /* allocate memory for vendor tuple array */
306 array = (struct snd_soc_tplg_vendor_array *)malloc(size);
307 if (!array) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700308 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700309 return -EINVAL;
310 }
311
312 /* read vendor tokens */
313 while (total_array_size < size) {
314 read_size = sizeof(struct snd_soc_tplg_vendor_array);
315 ret = fread(array, read_size, 1, file);
316 if (ret != 1)
317 return -EINVAL;
318
319 read_array(array);
320
321 /* parse comp tokens */
322 ret = sof_parse_tokens(&filewrite.config, comp_tokens,
323 ARRAY_SIZE(comp_tokens), array,
324 array->size);
325 if (ret != 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700326 fprintf(stderr, "error: parse filewrite tokens %d\n",
327 size);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700328 return -EINVAL;
329 }
330 total_array_size += array->size;
331 }
332
333 /* configure filewrite */
334 filewrite.fn = strdup(output_file);
335 filewrite.comp.id = comp_id;
336 filewrite.mode = FILE_WRITE;
337 *fw_id = comp_id;
338 filewrite.comp.hdr.size = sizeof(struct sof_ipc_comp_file);
339 filewrite.comp.type = SOF_COMP_FILEREAD;
340 filewrite.comp.pipeline_id = pipeline_id;
341
342 /* create filewrite component */
343 if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&filewrite) < 0) {
344 fprintf(stderr, "error: comp register\n");
345 return -EINVAL;
346 }
347
348 free(array);
349 free(filewrite.fn);
350 return 0;
351}
352
353/* load pda dapm widget */
354static int load_pga(struct sof *sof, int comp_id, int pipeline_id,
355 int size)
356{
357 struct sof_ipc_comp_volume volume;
358 struct snd_soc_tplg_vendor_array *array = NULL;
359 size_t total_array_size = 0, read_size;
360 int ret = 0;
361
362 /* allocate memory for vendor tuple array */
363 array = (struct snd_soc_tplg_vendor_array *)malloc(size);
364 if (!array) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700365 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700366 return -EINVAL;
367 }
368
369 /* read vendor tokens */
370 while (total_array_size < size) {
371 read_size = sizeof(struct snd_soc_tplg_vendor_array);
372 ret = fread(array, read_size, 1, file);
373 if (ret != 1)
374 return -EINVAL;
375 read_array(array);
376
377 /* parse volume tokens */
378 ret = sof_parse_tokens(&volume.config, comp_tokens,
379 ARRAY_SIZE(comp_tokens), array,
380 array->size);
381 if (ret != 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700382 fprintf(stderr, "error: parse pga tokens %d\n", size);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700383 return -EINVAL;
384 }
385 total_array_size += array->size;
386 }
387
388 /* configure volume */
389 volume.comp.id = comp_id;
390 volume.comp.hdr.size = sizeof(struct sof_ipc_comp_volume);
391 volume.comp.type = SOF_COMP_VOLUME;
392 volume.comp.pipeline_id = pipeline_id;
393
394 /* load volume component */
395 if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&volume) < 0) {
396 fprintf(stderr, "error: comp register\n");
397 return -EINVAL;
398 }
399
400 free(array);
401 return 0;
402}
403
404/* load scheduler dapm widget */
405static int load_pipeline(struct sof *sof, struct sof_ipc_pipe_new *pipeline,
406 int comp_id, int pipeline_id, int size, int *sched_id)
407{
408 struct snd_soc_tplg_vendor_array *array = NULL;
409 size_t total_array_size = 0, read_size;
410 int ret = 0;
411
412 /* configure pipeline */
413 pipeline->sched_id = *sched_id;
414 pipeline->comp_id = comp_id;
415 pipeline->pipeline_id = pipeline_id;
416
417 /* allocate memory for vendor tuple array */
418 array = (struct snd_soc_tplg_vendor_array *)malloc(size);
419 if (!array) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700420 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700421 return -EINVAL;
422 }
423
424 /* read vendor arrays */
425 while (total_array_size < size) {
426 read_size = sizeof(struct snd_soc_tplg_vendor_array);
427 ret = fread(array, read_size, 1, file);
428 if (ret != 1)
429 return -EINVAL;
430
431 ret = read_array(array);
432 if (ret < 0)
433 return -EINVAL;
434
435 /* parse scheduler tokens */
436 ret = sof_parse_tokens(pipeline, sched_tokens,
437 ARRAY_SIZE(sched_tokens), array,
438 array->size);
439 if (ret != 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700440 fprintf(stderr, "error: parse pipeline tokens %d\n",
441 size);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700442 return -EINVAL;
443 }
444 total_array_size += array->size;
445 }
446
447 /* Create pipeline */
448 if (ipc_pipeline_new(sof->ipc, pipeline) < 0) {
449 fprintf(stderr, "error: pipeline new\n");
450 return -EINVAL;
451 }
452
453 free(array);
454 return 0;
455}
456
457/* load dapm widget kcontrols
458 * we dont use controls in the testbench atm.
459 * so just skip to the next dapm widget
460 */
461static int load_controls(struct sof *sof, int num_kcontrols)
462{
463 struct snd_soc_tplg_ctl_hdr *ctl_hdr;
464 struct snd_soc_tplg_mixer_control *mixer_ctl;
465 struct snd_soc_tplg_enum_control *enum_ctl;
466 struct snd_soc_tplg_bytes_control *bytes_ctl;
467 size_t read_size, size;
468 int j, ret = 0;
469
470 /* allocate memory */
471 size = sizeof(struct snd_soc_tplg_ctl_hdr);
472 ctl_hdr = (struct snd_soc_tplg_ctl_hdr *)malloc(size);
473 if (!ctl_hdr) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700474 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700475 return -EINVAL;
476 }
477
478 size = sizeof(struct snd_soc_tplg_mixer_control);
479 mixer_ctl = (struct snd_soc_tplg_mixer_control *)malloc(size);
480 if (!mixer_ctl) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700481 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700482 return -EINVAL;
483 }
484
485 size = sizeof(struct snd_soc_tplg_enum_control);
486 enum_ctl = (struct snd_soc_tplg_enum_control *)malloc(size);
487 if (!enum_ctl) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700488 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700489 return -EINVAL;
490 }
491
492 size = sizeof(struct snd_soc_tplg_bytes_control);
493 bytes_ctl = (struct snd_soc_tplg_bytes_control *)malloc(size);
494 if (!bytes_ctl) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700495 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700496 return -EINVAL;
497 }
498
499 for (j = 0; j < num_kcontrols; j++) {
500 /* read control header */
501 read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
502 ret = fread(ctl_hdr, read_size, 1, file);
503 if (ret != 1)
504 return -EINVAL;
505
506 /* load control based on type */
507 switch (ctl_hdr->ops.info) {
508 case SND_SOC_TPLG_CTL_VOLSW:
509 case SND_SOC_TPLG_CTL_STROBE:
510 case SND_SOC_TPLG_CTL_VOLSW_SX:
511 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
512 case SND_SOC_TPLG_CTL_RANGE:
513 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
514
515 /* load mixer type control */
516 read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
517 fseek(file, read_size * -1, SEEK_CUR);
518 read_size = sizeof(struct snd_soc_tplg_mixer_control);
519 ret = fread(mixer_ctl, read_size, 1, file);
520 if (ret != 1)
521 return -EINVAL;
522
523 /* skip mixer private data */
524 fseek(file, mixer_ctl->priv.size, SEEK_CUR);
525 break;
526 case SND_SOC_TPLG_CTL_ENUM:
527 case SND_SOC_TPLG_CTL_ENUM_VALUE:
528 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
529 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
530 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
531
532 /* load enum type control */
533 read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
534 fseek(file, read_size * -1, SEEK_CUR);
535 read_size = sizeof(struct snd_soc_tplg_enum_control);
536 ret = fread(enum_ctl, read_size, 1, file);
537 if (ret != 1)
538 return -EINVAL;
539
540 /* skip enum private data */
541 fseek(file, enum_ctl->priv.size, SEEK_CUR);
542 break;
543 case SND_SOC_TPLG_CTL_BYTES:
544
545 /* load bytes type controls */
546 read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
547 fseek(file, read_size * -1, SEEK_CUR);
548 read_size = sizeof(struct snd_soc_tplg_bytes_control);
549 ret = fread(bytes_ctl, read_size, 1, file);
550 if (ret != 1)
551 return -EINVAL;
552
553 /* skip bytes private data */
554 fseek(file, bytes_ctl->priv.size, SEEK_CUR);
555 break;
556 default:
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700557 printf("info: control type not supported\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700558 return -EINVAL;
559 }
560 }
561
562 /* free all data */
563 free(mixer_ctl);
564 free(enum_ctl);
565 free(bytes_ctl);
566 free(ctl_hdr);
567 return 0;
568}
569
Ranjani Sridharan5b0965d2018-06-27 19:30:09 -0700570/* load src dapm widget */
571static int load_src(struct sof *sof, int comp_id, int pipeline_id,
572 int size)
573{
574 struct sof_ipc_comp_src src = {0};
575 struct snd_soc_tplg_vendor_array *array = NULL;
576 size_t total_array_size = 0, read_size;
577 int ret = 0;
578
579 /* allocate memory for vendor tuple array */
580 array = (struct snd_soc_tplg_vendor_array *)malloc(size);
581 if (!array) {
582 fprintf(stderr, "error: mem alloc for src vendor array\n");
583 return -EINVAL;
584 }
585
586 /* read vendor tokens */
587 while (total_array_size < size) {
588 read_size = sizeof(struct snd_soc_tplg_vendor_array);
589 ret = fread(array, read_size, 1, file);
590 if (ret != 1)
591 return -EINVAL;
592 read_array(array);
593
594 /* parse comp tokens */
595 ret = sof_parse_tokens(&src.config, comp_tokens,
596 ARRAY_SIZE(comp_tokens), array,
597 array->size);
598 if (ret != 0) {
599 fprintf(stderr, "error: parse src comp_tokens %d\n",
600 size);
601 return -EINVAL;
602 }
603
604 /* parse src tokens */
605 ret = sof_parse_tokens(&src, src_tokens,
606 ARRAY_SIZE(src_tokens), array,
607 array->size);
608 if (ret != 0) {
609 fprintf(stderr, "error: parse src tokens %d\n", size);
610 return -EINVAL;
611 }
612
613 total_array_size += array->size;
614
615 /* read next array */
616 array = (void *)array + array->size;
617 }
618
619 array = (void *)array - size;
620
Ranjani Sridharane822cfa2018-06-27 20:40:18 -0700621 /* set testbench input and output sample rate from topology */
622 if (!fs_out) {
623 fs_out = src.sink_rate;
624
625 if (!fs_in)
626 fs_in = src.source_rate;
627 else
628 src.source_rate = fs_in;
629 } else {
630 src.sink_rate = fs_out;
631 }
632
Ranjani Sridharan5b0965d2018-06-27 19:30:09 -0700633 /* configure src */
634 src.comp.id = comp_id;
635 src.comp.hdr.size = sizeof(struct sof_ipc_comp_src);
636 src.comp.type = SOF_COMP_SRC;
637 src.comp.pipeline_id = pipeline_id;
638
639 /* load src component */
640 if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&src) < 0) {
641 fprintf(stderr, "error: new src comp\n");
642 return -EINVAL;
643 }
644
645 free(array);
646 return 0;
647}
648
Ranjani Sridharan46704022018-05-31 19:29:05 -0700649/* load dapm widget */
650static int load_widget(struct sof *sof, int *fr_id, int *fw_id,
651 int *sched_id, char *bits_in,
652 struct comp_info *temp_comp_list,
653 struct sof_ipc_pipe_new *pipeline, int comp_id,
654 int comp_index, int pipeline_id)
655{
656 struct snd_soc_tplg_dapm_widget *widget;
657 char message[DEBUG_MSG_LEN];
658 size_t read_size, size;
659 int ret = 0;
660
661 /* allocate memory for widget */
662 size = sizeof(struct snd_soc_tplg_dapm_widget);
663 widget = (struct snd_soc_tplg_dapm_widget *)malloc(size);
664 if (!widget) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700665 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700666 return -EINVAL;
667 }
668
669 /* read widget data */
670 read_size = sizeof(struct snd_soc_tplg_dapm_widget);
671 ret = fread(widget, read_size, 1, file);
672 if (ret != 1)
673 return -EINVAL;
674
675 /*
676 * create a list with all widget info
677 * containing mapping between component names and ids
678 * which will be used for setting up component connections
679 */
680 temp_comp_list[comp_index].id = comp_id;
681 temp_comp_list[comp_index].name = strdup(widget->name);
682 temp_comp_list[comp_index].type = widget->id;
683 temp_comp_list[comp_index].pipeline_id = pipeline_id;
684
685 sprintf(message, "loading widget %s id %d\n",
686 temp_comp_list[comp_index].name,
687 temp_comp_list[comp_index].id);
688 debug_print(message);
689
690 /* register comp driver */
691 register_comp(temp_comp_list[comp_index].type);
692
693 /* load widget based on type */
694 switch (temp_comp_list[comp_index].type) {
695 /* load pga widget */
696 case(SND_SOC_TPLG_DAPM_PGA):
697 if (load_pga(sof, temp_comp_list[comp_index].id,
698 pipeline_id, widget->priv.size) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700699 fprintf(stderr, "error: load pga\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700700 return -EINVAL;
701 }
702 break;
703
704 /* replace pcm playback component with fileread in testbench */
705 case(SND_SOC_TPLG_DAPM_AIF_IN):
706 if (load_fileread(sof, temp_comp_list[comp_index].id,
707 pipeline_id, widget->priv.size, bits_in,
708 fr_id, sched_id) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700709 fprintf(stderr, "error: load fileread\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700710 return -EINVAL;
711 }
712 break;
713
714 /* replace dai in component with filewrite in testbench */
715 case(SND_SOC_TPLG_DAPM_DAI_IN):
716 if (load_filewrite(sof, temp_comp_list[comp_index].id,
717 pipeline_id, widget->priv.size,
718 fw_id) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700719 fprintf(stderr, "error: load filewrite\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700720 return -EINVAL;
721 }
722 break;
723
724 /* load buffer */
725 case(SND_SOC_TPLG_DAPM_BUFFER):
726 if (load_buffer(sof, temp_comp_list[comp_index].id,
727 pipeline_id, widget->priv.size) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700728 fprintf(stderr, "error: load buffer\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700729 return -EINVAL;
730 }
731 break;
732
733 /* load pipeline */
734 case(SND_SOC_TPLG_DAPM_SCHEDULER):
735 if (load_pipeline(sof, pipeline,
736 temp_comp_list[comp_index].id,
737 pipeline_id,
738 widget->priv.size,
739 sched_id) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700740 fprintf(stderr, "error: load buffer\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700741 return -EINVAL;
742 }
743 break;
744
Ranjani Sridharan5b0965d2018-06-27 19:30:09 -0700745 /* load src widget */
746 case(SND_SOC_TPLG_DAPM_SRC):
747 if (load_src(sof, temp_comp_list[comp_index].id,
748 pipeline_id, widget->priv.size) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700749 fprintf(stderr, "error: load src\n");
Ranjani Sridharan5b0965d2018-06-27 19:30:09 -0700750 return -EINVAL;
751 }
752 break;
753
Ranjani Sridharan46704022018-05-31 19:29:05 -0700754 /* unsupported widgets */
755 default:
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700756 printf("info: Widget type not supported %d\n",
Ranjani Sridharan46704022018-05-31 19:29:05 -0700757 widget->id);
758 break;
759 }
760
761 /* load widget kcontrols */
762 if (widget->num_kcontrols > 0)
763 if (load_controls(sof, widget->num_kcontrols) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700764 fprintf(stderr, "error: load buffer\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700765 return -EINVAL;
766 }
767
768 free(widget);
769 return 0;
770}
771
772/* parse topology file and set up pipeline */
773int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id,
Ranjani Sridharan03067c62018-06-27 15:09:25 -0700774 int *sched_id, char *bits_in, char *in_file,
775 char *out_file, struct shared_lib_table *library_table,
776 char *pipeline_msg)
Ranjani Sridharan46704022018-05-31 19:29:05 -0700777{
778 struct snd_soc_tplg_hdr *hdr;
779
780 struct comp_info *temp_comp_list = NULL;
781 struct sof_ipc_pipe_new pipeline;
782 char message[DEBUG_MSG_LEN];
783 int next_comp_id = 0, num_comps = 0;
784 int i, ret = 0;
785 size_t file_size, size;
786
Ranjani Sridharan46704022018-05-31 19:29:05 -0700787 /* open topology file */
Ranjani Sridharanf15512e2018-06-27 20:14:57 -0700788 file = fopen(tplg_file, "rb");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700789 if (!file) {
Ranjani Sridharanf15512e2018-06-27 20:14:57 -0700790 fprintf(stderr, "error: opening file %s\n", tplg_file);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700791 return -EINVAL;
792 }
793
Ranjani Sridharan03067c62018-06-27 15:09:25 -0700794 lib_table = library_table;
Ranjani Sridharan46704022018-05-31 19:29:05 -0700795
796 /* file size */
797 fseek(file, 0, SEEK_END);
798 file_size = ftell(file);
799 fseek(file, 0, SEEK_SET);
800
801 /* allocate memory */
802 size = sizeof(struct snd_soc_tplg_hdr);
803 hdr = (struct snd_soc_tplg_hdr *)malloc(size);
804 if (!hdr) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700805 fprintf(stderr, "error: mem alloc\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700806 return -EINVAL;
807 }
808
809 debug_print("topology parsing start\n");
810 while (1) {
811 /* read topology header */
812 ret = fread(hdr, sizeof(struct snd_soc_tplg_hdr), 1, file);
813 if (ret != 1)
814 return -EINVAL;
815
816 sprintf(message, "type: %x, size: 0x%x count: %d index: %d\n",
817 hdr->type, hdr->payload_size, hdr->count, hdr->index);
818 debug_print(message);
819
820 /* parse header and load the next block based on type */
821 switch (hdr->type) {
822 /* load dapm widget */
823 case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
824 sprintf(message, "number of DAPM widgets %d\n",
825 hdr->count);
826 debug_print(message);
827 size = sizeof(struct comp_info) * hdr->count;
828 temp_comp_list = (struct comp_info *)malloc(size);
829 num_comps = hdr->count;
830
831 for (i = 0; i < hdr->count; i++)
832 load_widget(sof, fr_id, fw_id, sched_id,
833 bits_in, temp_comp_list,
834 &pipeline, next_comp_id++,
835 i, hdr->index);
836 break;
837
838 /* set up component connections from pipeline graph */
839 case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
840 if (load_graph(sof, temp_comp_list, hdr->count,
841 num_comps, hdr->index) < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700842 fprintf(stderr, "error: pipeline graph\n");
Ranjani Sridharan46704022018-05-31 19:29:05 -0700843 return -EINVAL;
844 }
845
846 if (ftell(file) == file_size)
847 goto finish;
848 break;
849 default:
850 fseek(file, hdr->payload_size, SEEK_CUR);
851 if (ftell(file) == file_size)
852 goto finish;
853 break;
854 }
855 }
856finish:
857 debug_print("topology parsing end\n");
858 strcpy(pipeline_msg, pipeline_string);
859
860 /* free all data */
861 free(hdr);
862
863 for (i = 0; i < num_comps; i++)
864 free(temp_comp_list[i].name);
865
866 free(temp_comp_list);
867 fclose(file);
868 return 0;
869}
870
871/* parse vendor tokens in topology */
872int sof_parse_tokens(void *object, const struct sof_topology_token *tokens,
873 int count, struct snd_soc_tplg_vendor_array *array,
874 int priv_size)
875{
876 int asize;
877
878 while (priv_size > 0) {
879 asize = array->size;
880
881 /* validate asize */
882 if (asize < 0) { /* FIXME: A zero-size array makes no sense */
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700883 fprintf(stderr, "error: invalid array size 0x%x\n",
884 asize);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700885 return -EINVAL;
886 }
887
888 /* make sure there is enough data before parsing */
889 priv_size -= asize;
890
891 if (priv_size < 0) {
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700892 fprintf(stderr, "error: invalid array size 0x%x\n",
893 asize);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700894 return -EINVAL;
895 }
896
897 /* call correct parser depending on type */
898 switch (array->type) {
899 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
900 sof_parse_uuid_tokens(object, tokens, count,
901 array);
902 break;
903 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
904 sof_parse_string_tokens(object, tokens, count,
905 array);
906 break;
907 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
908 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
909 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
910 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
911 sof_parse_word_tokens(object, tokens, count,
912 array);
913 break;
914 default:
Ranjani Sridharan42b1a2e2018-06-27 19:39:20 -0700915 fprintf(stderr, "error: unknown token type %d\n",
916 array->type);
Ranjani Sridharan46704022018-05-31 19:29:05 -0700917 return -EINVAL;
918 }
Ranjani Sridharan46704022018-05-31 19:29:05 -0700919 }
920 return 0;
921}
922
923void sof_parse_word_tokens(void *object,
924 const struct sof_topology_token *tokens,
925 int count,
926 struct snd_soc_tplg_vendor_array *array)
927{
928 struct snd_soc_tplg_vendor_value_elem *elem;
929 int i, j;
930
931 /* parse element by element */
932 for (i = 0; i < array->num_elems; i++) {
933 elem = &array->value[i];
934
935 /* search for token */
936 for (j = 0; j < count; j++) {
937 /* match token type */
938 if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_WORD)
939 continue;
940
941 /* match token id */
942 if (tokens[j].token != elem->token)
943 continue;
944
945 /* matched - now load token */
946 tokens[j].get_token(elem, object, tokens[j].offset,
947 tokens[j].size);
948 }
949 }
950}
951
952void sof_parse_uuid_tokens(void *object,
953 const struct sof_topology_token *tokens,
954 int count,
955 struct snd_soc_tplg_vendor_array *array)
956{
957 struct snd_soc_tplg_vendor_uuid_elem *elem;
958 int i, j;
959
960 /* parse element by element */
961 for (i = 0; i < array->num_elems; i++) {
962 elem = &array->uuid[i];
963
964 /* search for token */
965 for (j = 0; j < count; j++) {
966 /* match token type */
967 if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID)
968 continue;
969
970 /* match token id */
971 if (tokens[j].token != elem->token)
972 continue;
973
974 /* matched - now load token */
975 tokens[j].get_token(elem, object, tokens[j].offset,
976 tokens[j].size);
977 }
978 }
979}
980
981void sof_parse_string_tokens(void *object,
982 const struct sof_topology_token *tokens,
983 int count,
984 struct snd_soc_tplg_vendor_array *array)
985{
986 struct snd_soc_tplg_vendor_string_elem *elem;
987 int i, j;
988
989 /* parse element by element */
990 for (i = 0; i < array->num_elems; i++) {
991 elem = &array->string[i];
992
993 /* search for token */
994 for (j = 0; j < count; j++) {
995 /* match token type */
996 if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING)
997 continue;
998
999 /* match token id */
1000 if (tokens[j].token != elem->token)
1001 continue;
1002
1003 /* matched - now load token */
1004 tokens[j].get_token(elem, object, tokens[j].offset,
1005 tokens[j].size);
1006 }
1007 }
1008}
1009
1010enum sof_ipc_frame find_format(const char *name)
1011{
1012 int i;
1013
1014 for (i = 0; i < ARRAY_SIZE(sof_frames); i++) {
1015 if (strcmp(name, sof_frames[i].name) == 0)
1016 return sof_frames[i].frame;
1017 }
1018
1019 /* use s32le if nothing is specified */
1020 return SOF_IPC_FRAME_S32_LE;
1021}
1022
1023int get_token_uint32_t(void *elem, void *object, uint32_t offset,
1024 uint32_t size)
1025{
1026 struct snd_soc_tplg_vendor_value_elem *velem = elem;
1027 uint32_t *val = object + offset;
1028
1029 *val = velem->value;
1030 return 0;
1031}
1032
1033int get_token_comp_format(void *elem, void *object, uint32_t offset,
1034 uint32_t size)
1035{
1036 struct snd_soc_tplg_vendor_string_elem *velem = elem;
1037 uint32_t *val = object + offset;
1038
1039 *val = find_format(velem->string);
1040 return 0;
1041}