[Sound-open-firmware] [PATCH 1/3] [RFC]tune: add common testbench common headers and source files
Seppo Ingalsuo
seppo.ingalsuo at linux.intel.com
Thu May 3 09:29:07 CEST 2018
On 03.05.2018 07:31, Ranjani Sridharan wrote:
> This patch adds the common header and source files required for all
> component testbench. These files include routines for parsing
> topology files, initializing sof ipc, scheduler and pipeline structures.
> They also provide simpler implementations for some of the SOF features
> such as tracing.
>
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> ---
> Makefile.am | 2 +-
> configure.ac | 4 +-
> tune/Makefile.am | 1 +
> tune/common/Makefile.am | 11 +
> tune/common/common_test.c | 461 ++++++++++++++++++++++++
> tune/common/common_test.h | 125 +++++++
> tune/common/common_tplg.c | 873 ++++++++++++++++++++++++++++++++++++++++++++++
> tune/common/common_tplg.h | 195 +++++++++++
> 8 files changed, 1670 insertions(+), 2 deletions(-)
> create mode 100644 tune/Makefile.am
> create mode 100644 tune/common/Makefile.am
> create mode 100644 tune/common/common_test.c
> create mode 100644 tune/common/common_test.h
> create mode 100644 tune/common/common_tplg.c
> create mode 100644 tune/common/common_tplg.h
>
> diff --git a/Makefile.am b/Makefile.am
> index ea5d746..2f494d9 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = rmbox topology
> +SUBDIRS = rmbox topology tune
> diff --git a/configure.ac b/configure.ac
> index b95c44c..d1c288d 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -12,7 +12,7 @@ dnl Initialize maintainer mode
> AM_MAINTAINER_MODE([enable])
>
> AC_PROG_CC
> -
> +LT_INIT
> AC_OUTPUT([
> Makefile
> rmbox/Makefile
> @@ -22,6 +22,8 @@ AC_OUTPUT([
> topology/m4/Makefile
> topology/sof/Makefile
> topology/test/Makefile
> + tune/Makefile
> + tune/common/Makefile
> ])
>
> echo "
> diff --git a/tune/Makefile.am b/tune/Makefile.am
> new file mode 100644
> index 0000000..e2e95a6
> --- /dev/null
> +++ b/tune/Makefile.am
> @@ -0,0 +1 @@
> +SUBDIRS = common
> diff --git a/tune/common/Makefile.am b/tune/common/Makefile.am
> new file mode 100644
> index 0000000..e435d07
> --- /dev/null
> +++ b/tune/common/Makefile.am
> @@ -0,0 +1,11 @@
> +noinst_LIBRARIES = libtb_common.a
> +
> +libtb_common_a_SOURCES = \
> + common_test.c \
> + common_tplg.c \
> + fileread.c \
> + filewrite.c
> +
> +libtb_common_a_CFLAGS = \
> + -I $(prefix)/include/sof
> + -g -Wall
> diff --git a/tune/common/common_test.c b/tune/common/common_test.c
> new file mode 100644
> index 0000000..1d4c9e8
> --- /dev/null
> +++ b/tune/common/common_test.c
> @@ -0,0 +1,461 @@
> +/* Simple test bench versions of SOF functions */
> +
> +/*
> + * Copyright (c) 2017, Intel Corporation
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * * Neither the name of the Intel Corporation nor the
> + * names of its contributors may be used to endorse or promote products
> + * derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.
> + *
> + * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
> + * Liam Girdwood <liam.r.girdwood at linux.intel.com>
> + * Keyon Jie <yang.jie at linux.intel.com>
> + * Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <time.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <math.h>
> +#include <sof/task.h>
> +#include <sof/alloc.h>
> +#include <sof/ipc.h>
> +#include <sof/dai.h>
> +#include <sof/dma.h>
> +#include <sof/work.h>
> +#include <sof/wait.h>
> +#include <sof/intel-ipc.h>
> +#include <sof/audio/pipeline.h>
> +#include "common_test.h"
> +#include "common_tplg.h"
> +
> +/* simplified host test bench versions for features */
> +struct dai *dai_get(uint32_t type, uint32_t index)
> +{
> + return NULL;
> +}
> +
> +struct dma *dma_get(int dmac_id)
> +{
> + return NULL;
> +}
> +
> +/* testbench ipc */
> +struct ipc *_ipc;
> +
> +int ipc_stream_send_position(struct comp_dev *cdev,
> + struct sof_ipc_stream_posn *posn)
> +{
> + return 0;
> +}
> +
> +int platform_ipc_init(struct ipc *ipc)
> +{
> + struct intel_ipc_data *iipc;
> + int i;
> +
> + _ipc = ipc;
> +
> + /* init ipc data */
> + iipc = malloc(sizeof(struct intel_ipc_data));
> + ipc_set_drvdata(_ipc, iipc);
> + _ipc->dsp_msg = NULL;
> + list_init(&ipc->empty_list);
> + list_init(&ipc->msg_list);
> + spinlock_init(&ipc->lock);
> +
> + for (i = 0; i < MSG_QUEUE_SIZE; i++)
> + list_item_prepend(&ipc->message[i].list, &ipc->empty_list);
> +
> + /* allocate page table buffer */
> + iipc->page_table = malloc(HOST_PAGE_SIZE);
> + if (iipc->page_table)
> + bzero(iipc->page_table, HOST_PAGE_SIZE);
> +
> + /* PM */
> + iipc->pm_prepare_D3 = 0;
> +
> + return 0;
> +}
> +
> +int ipc_stream_send_xrun(struct comp_dev *cdev,
> + struct sof_ipc_stream_posn *posn)
> +{
> + return 0;
> +}
> +
> +/* testbench trace definition */
> +
> +void _trace_error_atomic(uint32_t event)
> +{
> +}
Should this function include call to _trace_error(event) to see the
event in trace?
> +
> +void _trace_event_mbox_atomic(uint32_t event)
> +{
> +}
And this should call _trace_event()?
> +
> +static int test_bench_trace = 1;
> +
> +static char *get_trace_class(uint32_t trace_class)
> +{
> + switch (trace_class) {
> + case 1:
> + return "irq";
> + case 2:
> + return "ipc";
> + case 3:
> + return "pipe";
> + case 4:
> + return "host";
> + case 5:
> + return "dai";
> + case 6:
> + return "dma";
> + case 7:
> + return "ssp";
> + case 8:
> + return "comp";
> + case 9:
> + return "wait";
> + case 10:
> + return "lock";
> + case 11:
> + return "mem";
> + case 12:
> + return "mixer";
> + case 13:
> + return "buffer";
> + case 14:
> + return "volume";
> + case 15:
> + return "switch";
> + case 16:
> + return "mux";
> + case 17:
> + return "src";
> + case 18:
> + return "tone";
> + case 19:
> + return "eq_fir";
> + case 20:
> + return "eq_iir";
> + case 21:
> + return "sa";
> + default:
> + return "value";
> + }
> +}
> +
> +static char replace_blank(char x)
> +{
> + char y = x;
> +
> + if ((y < '!') || (y > 'z'))
> + y = ' ';
> +
> + return y;
> +}
> +
> +void _trace_event(uint32_t event)
> +{
> + char a, b, c;
> + char trace_class[10];
> +
> + if (test_bench_trace > 0) {
> + a = replace_blank((char) (event & 0xff));
> + b = replace_blank((char) ((event >> 8) & 0xff));
> + c = replace_blank((char) ((event >> 16) & 0xff));
> + strcpy(trace_class, get_trace_class(event >> 24));
> + if (strcmp(trace_class, "value") == 0)
> + printf("Trace value %d\n", event);
> + else
> + printf("Trace %s %c%c%c\n", trace_class, c, b, a);
> + }
> +}
Should we use printf(stderr, "") for traces? Then it could be simple to
direct the trace output to file with "2> trace.txt" if desired. Normally
stderr and stdout prints are not separated so there would be no impact
if no redirect used.
> +
> +void _trace_error(uint32_t event)
> +{
> + char a, b, c;
> +
> + if (test_bench_trace > 0) {
> + a = replace_blank((char) (event & 0xff));
> + b = replace_blank((char) ((event >> 8) & 0xff));
> + c = replace_blank((char) ((event >> 16) & 0xff));
> + printf("trace error: %s %c%c%c\n", get_trace_class(event >> 24),
> + c, b, a);
> + }
> +}
The same
> +
> +void tb_enable_trace(void)
> +{
> + test_bench_trace = 1;
> + printf("trace print enabled\n");
> +}
> +
> +void tb_disable_trace(void)
> +{
> + test_bench_trace = 0;
> + printf("trace print disabled\n");
> +}
> +
> +/* testbench mem alloc definition */
> +
> +void *rmalloc(int zone, uint32_t caps, size_t bytes)
> +{
> + return malloc(bytes);
> +}
> +
> +void *rzalloc(int zone, uint32_t caps, size_t bytes)
> +{
> + void *x;
> +
> + x = malloc(bytes);
> + bzero(x, bytes);
> + return x;
> +}
> +
> +void rfree(void *ptr)
> +{
> + free(ptr);
> +}
> +
> +void *rballoc(int zone, uint32_t caps, size_t bytes)
> +{
> + return malloc(bytes);
> +}
> +
> +void rbfree(void *ptr)
> +{
> + free(ptr);
> +}
> +
> +void *xthal_memcpy(void *dest, const void *src, size_t size)
> +{
> + return memcpy(dest, src, size);
> +}
> +
> +/* scheduler testbench definition */
> +
> +struct schedule_data {
> + spinlock_t lock;
> + struct list_item list; /* list of tasks in priority queue */
> + uint32_t clock;
> +};
> +static struct schedule_data *sch;
> +
> +void schedule_task_complete(struct task *task)
> +{
> +
> + list_item_del(&task->list);
> + task->state = TASK_STATE_COMPLETED;
> +}
> +
> +void schedule_task(struct task *task, uint64_t start, uint64_t deadline)
> +{
> +
> + task->deadline = deadline;
> + list_item_prepend(&task->list, &sch->list);
> + task->state = TASK_STATE_QUEUED;
> +
> + if (task->func)
> + task->func(task->data);
> +
> + schedule_task_complete(task);
> +}
> +
> +void schedule(void)
> +{
> +}
> +
> +int scheduler_init(struct sof *sof)
> +{
> + trace_pipe("ScI");
> +
> + sch = malloc(sizeof(*sch));
> + list_init(&sch->list);
> + spinlock_init(&sch->lock);
> +
> + return 0;
> +}
> +
> +void schedule_task_idle(struct task *task, uint64_t deadline)
> +{
> +}
> +
> +/* testbench work definition */
> +
> +void work_schedule_default(struct work *w, uint64_t timeout)
> +{
> +}
> +
> +void work_cancel_default(struct work *work)
> +{
> +}
> +
> +/* testbench helper functions for pipeline setup and trigger */
> +
> +int tb_pipeline_setup(struct sof *sof)
> +{
> +
> + /* init components */
> + sys_comp_init();
> +
> + /* init IPC */
> + if (ipc_init(sof) < 0) {
> + fprintf(stderr, "error: IPC init\n");
> + return -EINVAL;
> + }
> +
> + /* init scheduler */
> + if (scheduler_init(sof) < 0) {
> + fprintf(stderr, "error: scheduler init\n");
> + return -EINVAL;
> + }
> +
> + /* init pipeline system */
> + if (pipeline_init() < 0) {
> + fprintf(stderr, "error: pipeline init\n");
> + return -EINVAL;
> + }
> +
> + debug_print("ipc, scheduler and pipeline initialized\n");
> +
> + return 0;
> +}
> +
> +/* set up pcm params, prepare and trigger pipeline */
> +int tb_pipeline_start(struct ipc *ipc, int nch, char *bits_in,
> + struct sof_ipc_pipe_new *ipc_pipe)
> +{
> + struct ipc_comp_dev *pcm_dev;
> + struct pipeline *p;
> + struct comp_dev *cd;
> + int ret;
> +
> + ret = tb_pipeline_params(ipc, nch, bits_in, ipc_pipe);
> + if (ret < 0) {
> + printf("error: pipeline params\n");
> + return -EINVAL;
> + }
> +
> + /* Get IPC component device for pipeline */
> + pcm_dev = ipc_get_comp(ipc, ipc_pipe->sched_id);
> + if (pcm_dev == NULL) {
> + printf("error: ipc get comp\n");
> + return -EINVAL;
> + }
> +
> + /* Point to pipeline */
> + cd = pcm_dev->cd;
> + p = pcm_dev->cd->pipeline;
> +
> + /* Component prepare */
> + ret = pipeline_prepare(p, cd);
> +
> + /* Start the pipeline */
> + ret = pipeline_trigger(p, cd, COMP_TRIGGER_START);
> + if (ret < 0)
> + printf("Warning: Failed start pipeline command.\n");
> +
> + return ret;
> +}
> +
> +/* pipeline pcm params */
> +int tb_pipeline_params(struct ipc *ipc, int nch, char *bits_in,
> + struct sof_ipc_pipe_new *ipc_pipe)
> +{
> + int fs_period, ret = 0;
> + struct ipc_comp_dev *pcm_dev;
> + struct pipeline *p;
> + struct comp_dev *cd;
> + struct sof_ipc_pcm_params params;
> + int fs, deadline;
> +
> + deadline = ipc_pipe->deadline;
> + fs = deadline * ipc_pipe->frames_per_sched;
> +
> + /* Compute period from sample rates */
> + fs_period = (int) (0.9999 + fs * deadline / 1e6);
> +
> + params.comp_id = ipc_pipe->comp_id;
> + params.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
> + params.params.frame_fmt = find_format(bits_in);
> + params.params.direction = SOF_IPC_STREAM_PLAYBACK;
> + params.params.rate = fs;
> + params.params.channels = nch;
> + switch (params.params.frame_fmt) {
> + case(SOF_IPC_FRAME_S16_LE):
> + params.params.sample_container_bytes = 2;
> + params.params.sample_valid_bytes = 2;
> + params.params.host_period_bytes = fs_period * nch *
> + params.params.sample_container_bytes;
> + break;
> + case(SOF_IPC_FRAME_S24_4LE):
> + params.params.sample_container_bytes = 4;
> + params.params.sample_valid_bytes = 3;
> + params.params.host_period_bytes = fs_period * nch *
> + params.params.sample_container_bytes;
> + break;
> + case(SOF_IPC_FRAME_S32_LE):
> + params.params.sample_container_bytes = 4;
> + params.params.sample_valid_bytes = 4;
> + params.params.host_period_bytes = fs_period * nch *
> + params.params.sample_container_bytes;
> + break;
> + default:
> + printf("error: invalid frame format\n");
> + return -EINVAL;
> + }
> +
> + /* get scheduling component device for pipeline*/
> + pcm_dev = ipc_get_comp(ipc, ipc_pipe->sched_id);
> + if (pcm_dev == NULL) {
> + printf("error: ipc get comp\n");
> + return -EINVAL;
> + }
> +
> + /* point to pipeline */
> + cd = pcm_dev->cd;
> + p = pcm_dev->cd->pipeline;
> + if (p == NULL) {
> + printf("error: pipeline NULL\n");
> + return -EINVAL;
> + }
> +
> + /* pipeline params */
> + ret = pipeline_params(p, cd, ¶ms);
> + if (ret < 0)
> + printf("error: pipeline_params\n");
> +
> + return ret;
> +}
> +
> +void debug_print(char *message)
> +{
> +#ifdef DEBUG_PRINT
> + printf("debug: %s", message);
> +#endif
> +}
> diff --git a/tune/common/common_test.h b/tune/common/common_test.h
> new file mode 100644
> index 0000000..03968cd
> --- /dev/null
> +++ b/tune/common/common_test.h
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (c) 2017, Intel Corporation
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * * Neither the name of the Intel Corporation nor the
> + * names of its contributors may be used to endorse or promote products
> + * derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.
> + *
> + * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
> + * Liam Girdwood <liam.r.girdwood at linux.intel.com>
> + * Keyon Jie <yang.jie at linux.intel.com>
> + * Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +#ifndef _COMMON_TEST_H
> +#define _COMMON_TEST_H
> +
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <time.h>
> +#include <stdio.h>
> +#include <uapi/ipc.h>
> +#include <sof/sof.h>
> +#include <sof/audio/component.h>
> +#include <sof/audio/format.h>
> +
> +#define FILEREAD_FN_MAXLENGTH 256
> +#define FILEWRITE_FN_MAXLENGTH 256
> +#define DEBUG_MSG_LEN 256
> +
> +/* fileread component state */
> +struct fileread_state {
> + char fn[FILEREAD_FN_MAXLENGTH];
> + FILE *fh;
> + int reached_eof;
> + int n;
> +};
> +
> +/* fileread comp data */
> +struct fileread_comp_data {
> + uint32_t period_bytes;
> + uint32_t channels;
> + uint32_t frame_bytes;
> + uint32_t rate;
> + struct fileread_state frs;
> + int (*fileread_func)(struct comp_dev *dev, struct comp_buffer *sink,
> + struct comp_buffer *source, uint32_t frames);
> +
> +};
> +
> +/* filewrite component state */
> +struct filewrite_state {
> + char fn[FILEWRITE_FN_MAXLENGTH];
> + FILE *fh;
> + int write_fail;
> + int n;
> + int (*filewrite_func)(struct comp_dev *dev, struct comp_buffer *sink,
> + struct comp_buffer *source, uint32_t frames);
> +
> +};
> +
> +/* fileread comp data */
> +struct filewrite_comp_data {
> + uint32_t period_bytes;
> + uint32_t channels;
> + uint32_t frame_bytes;
> + uint32_t rate;
> + struct filewrite_state fws;
> + int (*filewrite_func)(struct comp_dev *dev, struct comp_buffer *sink,
> + struct comp_buffer *source, uint32_t frames);
> +
> +};
> +
> +/* fileread/filewrite ipc comp */
> +struct sof_ipc_comp_fileread {
> + struct sof_ipc_comp comp;
> + struct sof_ipc_comp_config config;
> + char *fn;
> +};
> +
> +struct sof_ipc_comp_filewrite {
> + struct sof_ipc_comp comp;
> + struct sof_ipc_comp_config config;
> + char *fn;
> +};
> +
> +int scheduler_init(struct sof *sof);
> +
> +void sys_comp_fileread_init(void);
> +
> +void sys_comp_filewrite_init(void);
> +
> +int tb_pipeline_setup(struct sof *sof);
> +
> +int tb_pipeline_start(struct ipc *ipc, int nch, char *bits_in,
> + struct sof_ipc_pipe_new *ipc_pipe);
> +
> +int tb_pipeline_params(struct ipc *ipc, int nch, char *bits_in,
> + struct sof_ipc_pipe_new *ipc_pipe);
> +
> +void tb_enable_trace(void);
> +
> +void tb_disable_trace(void);
> +
> +void debug_print(char *message);
> +
> +#endif
> diff --git a/tune/common/common_tplg.c b/tune/common/common_tplg.c
> new file mode 100644
> index 0000000..f59a386
> --- /dev/null
> +++ b/tune/common/common_tplg.c
> @@ -0,0 +1,873 @@
> +/*
> + * Copyright (c) 2017, Intel Corporation
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * * Neither the name of the Intel Corporation nor the
> + * names of its contributors may be used to endorse or promote products
> + * derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.
> + *
> + * Author: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + * Liam Girdwood <liam.r.girdwood at linux.intel.com>
> + */
> +
> +/*
> + * Topology parser to parse topology bin file
> + * and set up components and pipeline
> + */
> +
> +#include "common_tplg.h"
> +#include <sof/ipc.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +FILE *file;
> +char *input_file;
> +char *output_file;
> +
> +/* read vendor tuples array from topology */
> +static int read_array(struct snd_soc_tplg_vendor_array *array)
> +{
> + int j, ret = 0;
> + size_t size;
> +
> + switch (array->type) {
> + case SND_SOC_TPLG_TUPLE_TYPE_UUID:
> + ;
> + /* copy uuid elems into array */
> + struct snd_soc_tplg_vendor_uuid_elem uuid;
> +
> + for (j = 0; j < array->num_elems; j++) {
> + size = sizeof(struct snd_soc_tplg_vendor_uuid_elem);
> + ret = fread(&uuid, size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + memcpy(&array->uuid[j], &uuid, size);
> + }
> + break;
> + case SND_SOC_TPLG_TUPLE_TYPE_STRING:
> + ;
> + /* copy string elems into array */
> + struct snd_soc_tplg_vendor_string_elem string;
> +
> + for (j = 0; j < array->num_elems; j++) {
> + size = sizeof(struct snd_soc_tplg_vendor_string_elem);
> + ret = fread(&string, size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + memcpy(&array->string[j], &string, size);
> + }
> + break;
> + case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
> + case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
> + case SND_SOC_TPLG_TUPLE_TYPE_WORD:
> + case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
> + ;
> + /* copy value elems into array */
> + struct snd_soc_tplg_vendor_value_elem value;
> +
> + for (j = 0; j < array->num_elems; j++) {
> + size = sizeof(struct snd_soc_tplg_vendor_value_elem);
> + ret = fread(&value, size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + memcpy(&array->value[j], &value, size);
> + }
> + break;
> + default:
> + printf("error: unknown token type %d\n", array->type);
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +/* load pipeline graph DAPM widget*/
> +static int load_graph(struct sof *sof, struct comp_info *temp_comp_list,
> + int count, int num_comps, int pipeline_id)
> +{
> + struct sof_ipc_pipe_comp_connect connection;
> + struct snd_soc_tplg_dapm_graph_elem *graph_elem;
> + size_t size;
> + int i, j, ret = 0;
> +
> + /* allocate memory for graph elem */
> + size = sizeof(struct snd_soc_tplg_dapm_graph_elem);
> + graph_elem = (struct snd_soc_tplg_dapm_graph_elem *)malloc(size);
> + if (!graph_elem) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + /* set up component connections */
> + connection.source_id = connection.sink_id = -1;
> + for (i = 0; i < count; i++) {
> + size = sizeof(struct snd_soc_tplg_dapm_graph_elem);
> + ret = fread(graph_elem, size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + for (j = 0; j < num_comps; j++) {
> + /* look up component id from the component list */
> + if (strcmp(temp_comp_list[j].name,
> + graph_elem->source) == 0)
> + connection.source_id = temp_comp_list[j].id;
> + if (strcmp(temp_comp_list[j].name,
> + graph_elem->sink) == 0)
> + connection.sink_id = temp_comp_list[j].id;
> + }
> + /* connect source and sink */
> + if (connection.source_id != -1 && connection.sink_id != -1)
> + if (ipc_comp_connect(sof->ipc, &connection) < 0) {
> + fprintf(stderr, "error: comp connect\n");
> + return -EINVAL;
> + }
> + }
> +
> + /* pipeline complete after pipeline connections are established */
> + for (i = 0; i < num_comps; i++) {
> + if (temp_comp_list[i].pipeline_id == pipeline_id &&
> + temp_comp_list[i].type == SND_SOC_TPLG_DAPM_SCHEDULER)
> + ipc_pipeline_complete(sof->ipc, temp_comp_list[i].id);
> + }
> +
> + free(graph_elem);
> + return 0;
> +}
> +
> +/* load buffer DAPM widget */
> +static int load_buffer(struct sof *sof, int comp_id, int pipeline_id, int size)
> +{
> + struct sof_ipc_buffer buffer;
> + struct snd_soc_tplg_vendor_array *array = NULL;
> + int ret = 0;
> +
> + /* configure buffer */
> + buffer.comp.id = comp_id;
> + buffer.comp.pipeline_id = pipeline_id;
> +
> + /* allocate memory for vendor tuple array */
> + array = (struct snd_soc_tplg_vendor_array *)malloc(size);
> + ret = fread(array, sizeof(struct snd_soc_tplg_vendor_array), 1, file);
> + if (ret != 1)
> + return -EINVAL;
> +
> + read_array(array);
> + /* parse buffer tokens */
> + ret = sof_parse_tokens(&buffer, buffer_tokens,
> + ARRAY_SIZE(buffer_tokens), array,
> + size);
> +
> + /* create buffer component */
> + if (ipc_buffer_new(sof->ipc, &buffer) < 0) {
> + fprintf(stderr, "error: buffer new\n");
> + return -EINVAL;
> + }
> + free(array);
> + return 0;
> +}
> +
> +/* load fileread component */
> +static int load_fileread(struct sof *sof, int comp_id, int pipeline_id,
> + int size, char *bits_in, int *fr_id, int *sched_id)
> +{
> + struct sof_ipc_comp_fileread fileread;
> + struct snd_soc_tplg_vendor_array *array = NULL;
> + size_t total_array_size = 0, read_size;
> + int ret = 0;
> +
> + fileread.config.frame_fmt = find_format(bits_in);
> +
> + /* allocate memory for vendor tuple array */
> + array = (struct snd_soc_tplg_vendor_array *)malloc(size);
> + if (!array) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + /* read vendor tokens */
> + while (total_array_size < size) {
> + read_size = sizeof(struct snd_soc_tplg_vendor_array);
> + ret = fread(array, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + read_array(array);
> + /* parse comp tokens */
> + ret = sof_parse_tokens(&fileread.config, comp_tokens,
> + ARRAY_SIZE(comp_tokens), array,
> + array->size);
> + if (ret != 0) {
> + printf("error: parse fileread tokens %d\n", size);
> + return -EINVAL;
> + }
> + total_array_size += array->size;
> + }
> +
> + /* configure fileread */
> + fileread.fn = input_file;
> + fileread.comp.id = comp_id;
> + /* use fileread comp as scheduling comp */
> + *fr_id = *sched_id = comp_id;
> + fileread.comp.hdr.size = sizeof(struct sof_ipc_comp_fileread);
> + fileread.comp.type = SOF_COMP_FILEREAD;
> + fileread.comp.pipeline_id = pipeline_id;
> +
> + /* create fileread component */
> + if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&fileread) < 0) {
> + fprintf(stderr, "error: comp register\n");
> + return -EINVAL;
> + }
> +
> + free(array);
> + return 0;
> +}
> +
> +/* load filewrite component */
> +static int load_filewrite(struct sof *sof, int comp_id, int pipeline_id,
> + int size, int *fw_id)
> +{
> +
> + struct sof_ipc_comp_filewrite filewrite;
> + struct snd_soc_tplg_vendor_array *array = NULL;
> + size_t total_array_size = 0, read_size;
> + int ret = 0;
> +
> + /* allocate memory for vendor tuple array */
> + array = (struct snd_soc_tplg_vendor_array *)malloc(size);
> + if (!array) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + /* read vendor tokens */
> + while (total_array_size < size) {
> + read_size = sizeof(struct snd_soc_tplg_vendor_array);
> + ret = fread(array, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> +
> + read_array(array);
> + /* parse comp tokens */
> + ret = sof_parse_tokens(&filewrite.config, comp_tokens,
> + ARRAY_SIZE(comp_tokens), array,
> + array->size);
> + if (ret != 0) {
> + printf("error: parse filewrite tokens %d\n", size);
> + return -EINVAL;
> + }
> + total_array_size += array->size;
> + }
> +
> + /* configure filewrite */
> + filewrite.fn = output_file;
> + filewrite.comp.id = comp_id;
> + *fw_id = comp_id;
> + filewrite.comp.hdr.size = sizeof(struct sof_ipc_comp_filewrite);
> + filewrite.comp.type = SOF_COMP_FILEWRITE;
> + filewrite.comp.pipeline_id = pipeline_id;
> +
> + /* create filewrite component */
> + if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&filewrite) < 0) {
> + fprintf(stderr, "error: comp register\n");
> + return -EINVAL;
> + }
> +
> + free(array);
> + return 0;
> +}
> +
> +/* load pda dapm widget */
> +static int load_pga(struct sof *sof, int comp_id, int pipeline_id,
> + int size)
> +{
> + struct sof_ipc_comp_volume volume;
> + struct snd_soc_tplg_vendor_array *array = NULL;
> + size_t total_array_size = 0, read_size;
> + int ret = 0;
> +
> + /* allocate memory for vendor tuple array */
> + array = (struct snd_soc_tplg_vendor_array *)malloc(size);
> + if (!array) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + /* read vendor tokens */
> + while (total_array_size < size) {
> + read_size = sizeof(struct snd_soc_tplg_vendor_array);
> + ret = fread(array, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + read_array(array);
> +
> + /* parse volume tokens */
> + ret = sof_parse_tokens(&volume.config, comp_tokens,
> + ARRAY_SIZE(comp_tokens), array,
> + array->size);
> + if (ret != 0) {
> + printf("error: parse pga tokens %d\n", size);
> + return -EINVAL;
> + }
> + total_array_size += array->size;
> + }
> +
> + /* configure volume */
> + volume.comp.id = comp_id;
> + volume.comp.hdr.size = sizeof(struct sof_ipc_comp_volume);
> + volume.comp.type = SOF_COMP_VOLUME;
> + volume.comp.pipeline_id = pipeline_id;
> +
> + /* load volume component */
> + if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&volume) < 0) {
> + fprintf(stderr, "error: comp register\n");
> + return -EINVAL;
> + }
> +
> + free(array);
> + return 0;
> +}
> +
> +/* load scheduler dapm widget */
> +static int load_pipeline(struct sof *sof, struct sof_ipc_pipe_new *pipeline,
> + int comp_id, int pipeline_id, int size, int *sched_id)
> +{
> + struct snd_soc_tplg_vendor_array *array = NULL;
> + size_t total_array_size = 0, read_size;
> + int ret = 0;
> +
> + /* configure pipeline */
> + pipeline->sched_id = *sched_id;
> + pipeline->comp_id = comp_id;
> + pipeline->pipeline_id = pipeline_id;
> +
> + /* allocate memory for vendor tuple array */
> + array = (struct snd_soc_tplg_vendor_array *)malloc(size);
> + if (!array) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + /* read vendor array */
> + while (total_array_size < size) {
> + read_size = sizeof(struct snd_soc_tplg_vendor_array);
> + ret = fread(array, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + ret = read_array(array);
> + if (ret < 0)
> + return -EINVAL;
> + /* parse scheduler tokens */
> + ret = sof_parse_tokens(pipeline, sched_tokens,
> + ARRAY_SIZE(sched_tokens), array,
> + array->size);
> + if (ret != 0) {
> + printf("error: parse pipeline tokens %d\n", size);
> + return -EINVAL;
> + }
> + total_array_size += array->size;
> + }
> +
> + /* Create pipeline */
> + if (ipc_pipeline_new(sof->ipc, pipeline) < 0) {
> + fprintf(stderr, "error: pipeline new\n");
> + return -EINVAL;
> + }
> +
> + free(array);
> + return 0;
> +}
> +
> +/* load dapm widget kcontrols
> + * we dont use controls in the testbench atm.
> + * so just skip to the next dapm widget
> + */
> +static int load_controls(struct sof *sof, int num_kcontrols)
> +{
> + struct snd_soc_tplg_ctl_hdr *ctl_hdr;
> + struct snd_soc_tplg_mixer_control *mixer_ctl;
> + struct snd_soc_tplg_enum_control *enum_ctl;
> + struct snd_soc_tplg_bytes_control *bytes_ctl;
> + size_t read_size, size;
> + int j, ret = 0;
> +
> + /* allocate memory */
> + size = sizeof(struct snd_soc_tplg_ctl_hdr);
> + ctl_hdr = (struct snd_soc_tplg_ctl_hdr *)malloc(size);
> + if (!ctl_hdr) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + size = sizeof(struct snd_soc_tplg_mixer_control);
> + mixer_ctl = (struct snd_soc_tplg_mixer_control *)malloc(size);
> + if (!mixer_ctl) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + size = sizeof(struct snd_soc_tplg_enum_control);
> + enum_ctl = (struct snd_soc_tplg_enum_control *)malloc(size);
> + if (!enum_ctl) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + size = sizeof(struct snd_soc_tplg_bytes_control);
> + bytes_ctl = (struct snd_soc_tplg_bytes_control *)malloc(size);
> + if (!bytes_ctl) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + for (j = 0; j < num_kcontrols; j++) {
> + /* read control header */
> + read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
> + ret = fread(ctl_hdr, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + /* load control based on type */
> + switch (ctl_hdr->ops.info) {
> + case SND_SOC_TPLG_CTL_VOLSW:
> + case SND_SOC_TPLG_CTL_STROBE:
> + case SND_SOC_TPLG_CTL_VOLSW_SX:
> + case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
> + case SND_SOC_TPLG_CTL_RANGE:
> + case SND_SOC_TPLG_DAPM_CTL_VOLSW:
> + /* load mixer type control */
> + read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
> + fseek(file, read_size * -1, SEEK_CUR);
> + read_size = sizeof(struct snd_soc_tplg_mixer_control);
> + ret = fread(mixer_ctl, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + /* skip mixer private data */
> + fseek(file, mixer_ctl->priv.size, SEEK_CUR);
> + break;
> + case SND_SOC_TPLG_CTL_ENUM:
> + case SND_SOC_TPLG_CTL_ENUM_VALUE:
> + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
> + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
> + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
> + /* load enum type control */
> + read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
> + fseek(file, read_size * -1, SEEK_CUR);
> + read_size = sizeof(struct snd_soc_tplg_enum_control);
> + ret = fread(enum_ctl, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + /* skip enum private data */
> + fseek(file, enum_ctl->priv.size, SEEK_CUR);
> + break;
> + case SND_SOC_TPLG_CTL_BYTES:
> + /* load bytes type controls */
> + read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
> + fseek(file, read_size * -1, SEEK_CUR);
> + read_size = sizeof(struct snd_soc_tplg_bytes_control);
> + ret = fread(bytes_ctl, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> + /* skip bytes private data */
> + fseek(file, bytes_ctl->priv.size, SEEK_CUR);
> + break;
> + default:
> + printf("control type not supported\n");
> + return -EINVAL;
> + }
> + }
> +
> + /* free all data */
> + free(mixer_ctl);
> + free(enum_ctl);
> + free(bytes_ctl);
> + free(ctl_hdr);
> + return 0;
> +}
> +
> +/* load dapm widget */
> +static int load_widget(struct sof *sof, int *fr_id, int *fw_id,
> + int *sched_id, char *bits_in,
> + struct comp_info *temp_comp_list,
> + struct sof_ipc_pipe_new *pipeline, int comp_id,
> + int comp_index, int pipeline_id)
> +{
> + struct snd_soc_tplg_dapm_widget *widget;
> + char message[DEBUG_MSG_LEN];
> + size_t read_size, size;
> + int ret = 0;
> +
> + /* allocate memory for widget */
> + size = sizeof(struct snd_soc_tplg_dapm_widget);
> + widget = (struct snd_soc_tplg_dapm_widget *)malloc(size);
> + if (!widget) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + /* read widget data */
> + read_size = sizeof(struct snd_soc_tplg_dapm_widget);
> + ret = fread(widget, read_size, 1, file);
> + if (ret != 1)
> + return -EINVAL;
> +
> + /*
> + * create a list with all widget info
> + * containing mapping between component names and ids
> + * which will be used for setting up component connections
> + */
> + temp_comp_list[comp_index].id = comp_id;
> + strcpy(temp_comp_list[comp_index].name, widget->name);
> + temp_comp_list[comp_index].type = widget->id;
> + temp_comp_list[comp_index].pipeline_id = pipeline_id;
> +
> + sprintf(message, "loading widget %s id %d\n",
> + temp_comp_list[comp_index].name,
> + temp_comp_list[comp_index].id);
> + debug_print(message);
> +
> + /* load widget based on type */
> + switch (temp_comp_list[comp_index].type) {
> + case(SND_SOC_TPLG_DAPM_PGA):
> + /* load pga widget */
> + sys_comp_volume_init();
> + if (load_pga(sof, temp_comp_list[comp_index].id,
> + pipeline_id, widget->priv.size) < 0) {
> + printf("error: load pga\n");
> + return -EINVAL;
> + }
> + break;
> + case(SND_SOC_TPLG_DAPM_AIF_IN):
> + sys_comp_fileread_init();
> + /* replace pcm playback component with fileread in testbench */
> + if (load_fileread(sof, temp_comp_list[comp_index].id,
> + pipeline_id, widget->priv.size, bits_in,
> + fr_id, sched_id) < 0) {
> + printf("error: load fileread\n");
> + return -EINVAL;
> + }
> + break;
> + case(SND_SOC_TPLG_DAPM_DAI_IN):
> + sys_comp_filewrite_init();
> + /* replace dai in component with filewrite in testbench */
> + if (load_filewrite(sof, temp_comp_list[comp_index].id,
> + pipeline_id, widget->priv.size,
> + fw_id) < 0) {
> + printf("error: load filewrite\n");
> + return -EINVAL;
> + }
> + break;
> + case(SND_SOC_TPLG_DAPM_BUFFER):
> + /* load buffer */
> + if (load_buffer(sof, temp_comp_list[comp_index].id,
> + pipeline_id, widget->priv.size) < 0) {
> + printf("error: load buffer\n");
> + return -EINVAL;
> + }
> + break;
> + case(SND_SOC_TPLG_DAPM_SCHEDULER):
> + /* load pipeline */
> + if (load_pipeline(sof, pipeline,
> + temp_comp_list[comp_index].id,
> + pipeline_id,
> + widget->priv.size,
> + sched_id) < 0) {
> + printf("error: load buffer\n");
> + return -EINVAL;
> + }
> + break;
> + default:
> + printf("Widget type not supported %d\n",
> + widget->id);
> + break;
> + }
> + /* load widget kcontrols */
> + if (widget->num_kcontrols > 0)
> + if (load_controls(sof, widget->num_kcontrols) < 0) {
> + printf("error: load buffer\n");
> + return -EINVAL;
> + }
> + free(widget);
> + return 0;
> +}
> +
> +/* parse topology file and set up pipeline */
> +int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id,
> + int *sched_id, char *bits_in, char *in_file,
> + char *out_file)
> +{
> + struct snd_soc_tplg_hdr *hdr;
> +
> + struct comp_info *temp_comp_list = NULL;
> + struct sof_ipc_pipe_new pipeline;
> + char message[DEBUG_MSG_LEN];
> + int next_comp_id = 0, num_comps = 0;
> + int i, ret = 0;
> + size_t file_size, size;
> +
> + /* open topology file */
> + file = fopen(filename, "rb");
> + if (!file) {
> + fprintf(stderr, "error: opening file %s", filename);
> + return -EINVAL;
> + }
> +
> + /* set up fileread and filewrite file names */
> + input_file = malloc(strlen(in_file));
> + strcpy(input_file, in_file);
> + output_file = malloc(strlen(out_file));
> + strcpy(output_file, out_file);
> +
> + /* file size */
> + fseek(file, 0, SEEK_END);
> + file_size = ftell(file);
> + fseek(file, 0, SEEK_SET);
> +
> + /* allocate memory */
> + size = sizeof(struct snd_soc_tplg_hdr);
> + hdr = (struct snd_soc_tplg_hdr *)malloc(size);
> + if (!hdr) {
> + printf("error: mem alloc\n");
> + return -EINVAL;
> + }
> +
> + debug_print("topology parsing start\n");
> + while (1) {
> + /* read topology header */
> + ret = fread(hdr, sizeof(struct snd_soc_tplg_hdr), 1, file);
> + if (ret != 1)
> + return -EINVAL;
> +
> + sprintf(message, "type: %x, size: 0x%x count: %d index: %d\n",
> + hdr->type, hdr->payload_size, hdr->count, hdr->index);
> + debug_print(message);
> +
> + /* parse header and load the next block based on type */
> + switch (hdr->type) {
> + case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
> + /* load dapm widget */
> + sprintf(message, "number of DAPM widgets %d\n",
> + hdr->count);
> + debug_print(message);
> + size = sizeof(struct comp_info) * hdr->count;
> + temp_comp_list = (struct comp_info *)malloc(size);
> + num_comps = hdr->count;
> +
> + for (i = 0; i < hdr->count; i++)
> + load_widget(sof, fr_id, fw_id, sched_id,
> + bits_in, temp_comp_list,
> + &pipeline, next_comp_id++,
> + i, hdr->index);
> + break;
> + case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
> + /* set up component connections from pipeline graph */
> + if (load_graph(sof, temp_comp_list, hdr->count,
> + num_comps, hdr->index) < 0) {
> + printf("error: pipeline graph\n");
> + return -EINVAL;
> + }
> +
> + if (ftell(file) == file_size)
> + goto finish;
> + break;
> + default:
> + fseek(file, hdr->payload_size, SEEK_CUR);
> + if (ftell(file) == file_size)
> + goto finish;
> + break;
> + }
> + }
> +finish:
> + debug_print("topology parsing end\n");
> + /* free all data */
> + free(hdr);
> + free(temp_comp_list);
> + fclose(file);
> + return 0;
> +}
> +
> +/* parse vendor tokens in topology */
> +int sof_parse_tokens(void *object, const struct sof_topology_token *tokens,
> + int count, struct snd_soc_tplg_vendor_array *array,
> + int priv_size)
> +{
> + int asize;
> +
> + while (priv_size > 0) {
> + asize = array->size;
> +
> + /* validate asize */
> + if (asize < 0) { /* FIXME: A zero-size array makes no sense */
> + printf("error: invalid array size 0x%x\n", asize);
> + return -EINVAL;
> + }
> +
> + /* make sure there is enough data before parsing */
> + priv_size -= asize;
> +
> + if (priv_size < 0) {
> + printf("error: invalid array size 0x%x\n", asize);
> + return -EINVAL;
> + }
> +
> + /* call correct parser depending on type */
> + switch (array->type) {
> + case SND_SOC_TPLG_TUPLE_TYPE_UUID:
> + sof_parse_uuid_tokens(object, tokens, count,
> + array);
> + break;
> + case SND_SOC_TPLG_TUPLE_TYPE_STRING:
> + sof_parse_string_tokens(object, tokens, count,
> + array);
> + break;
> + case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
> + case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
> + case SND_SOC_TPLG_TUPLE_TYPE_WORD:
> + case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
> + sof_parse_word_tokens(object, tokens, count,
> + array);
> + break;
> + default:
> + printf("error: unknown token type %d\n", array->type);
> + return -EINVAL;
> + }
> +
> + /* next array */
> + array = (void *)array + asize;
> + }
> + return 0;
> +}
> +
> +void sof_parse_word_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array)
> +{
> + struct snd_soc_tplg_vendor_value_elem *elem;
> + int i, j;
> +
> + /* parse element by element */
> + for (i = 0; i < array->num_elems; i++) {
> + elem = &array->value[i];
> +
> + /* search for token */
> + for (j = 0; j < count; j++) {
> + /* match token type */
> + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_WORD)
> + continue;
> +
> + /* match token id */
> + if (tokens[j].token != elem->token)
> + continue;
> +
> + /* matched - now load token */
> + tokens[j].get_token(elem, object, tokens[j].offset,
> + tokens[j].size);
> + }
> + }
> +}
> +
> +void sof_parse_uuid_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array)
> +{
> + struct snd_soc_tplg_vendor_uuid_elem *elem;
> + int i, j;
> +
> + /* parse element by element */
> + for (i = 0; i < array->num_elems; i++) {
> + elem = &array->uuid[i];
> +
> + /* search for token */
> + for (j = 0; j < count; j++) {
> + /* match token type */
> + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID)
> + continue;
> +
> + /* match token id */
> + if (tokens[j].token != elem->token)
> + continue;
> +
> + /* matched - now load token */
> + tokens[j].get_token(elem, object, tokens[j].offset,
> + tokens[j].size);
> + }
> + }
> +}
> +
> +void sof_parse_string_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array)
> +{
> + struct snd_soc_tplg_vendor_string_elem *elem;
> + int i, j;
> +
> + /* parse element by element */
> + for (i = 0; i < array->num_elems; i++) {
> + elem = &array->string[i];
> +
> + /* search for token */
> + for (j = 0; j < count; j++) {
> + /* match token type */
> + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING)
> + continue;
> +
> + /* match token id */
> + if (tokens[j].token != elem->token)
> + continue;
> +
> + /* matched - now load token */
> + tokens[j].get_token(elem, object, tokens[j].offset,
> + tokens[j].size);
> + }
> + }
> +}
> +
> +enum sof_ipc_frame find_format(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(sof_frames); i++) {
> + if (strcmp(name, sof_frames[i].name) == 0)
> + return sof_frames[i].frame;
> + }
> +
> + /* use s32le if nothing is specified */
> + return SOF_IPC_FRAME_S32_LE;
> +}
> +
> +int get_token_uint32_t(void *elem, void *object, uint32_t offset,
> + uint32_t size)
> +{
> + struct snd_soc_tplg_vendor_value_elem *velem = elem;
> + uint32_t *val = object + offset;
> +
> + *val = velem->value;
> + return 0;
> +}
> +
> +int get_token_comp_format(void *elem, void *object, uint32_t offset,
> + uint32_t size)
> +{
> + struct snd_soc_tplg_vendor_string_elem *velem = elem;
> + uint32_t *val = object + offset;
> +
> + *val = find_format(velem->string);
> + return 0;
> +}
> diff --git a/tune/common/common_tplg.h b/tune/common/common_tplg.h
> new file mode 100644
> index 0000000..ea7d12c
> --- /dev/null
> +++ b/tune/common/common_tplg.h
> @@ -0,0 +1,195 @@
> +/*
> + * Copyright (c) 2017, Intel Corporation
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * * Neither the name of the Intel Corporation nor the
> + * names of its contributors may be used to endorse or promote products
> + * derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.
> + *
> + * Author: Liam Girdwood <liam.r.girdwood at linux.intel.com>
> + * Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +#ifndef _COMMON_TPLG_H
> +#define _COMMON_TPLG_H
> +
> +#include <sound/asoc.h>
> +#include "common_test.h"
> +
> +/*
> + * Tokens - must match values in topology configurations
> + */
> +
> +/* buffers */
> +#define SOF_TKN_BUF_SIZE 100
> +#define SOF_TKN_BUF_CAPS 101
> +
> +/* scheduling */
> +#define SOF_TKN_SCHED_DEADLINE 200
> +#define SOF_TKN_SCHED_PRIORITY 201
> +#define SOF_TKN_SCHED_MIPS 202
> +#define SOF_TKN_SCHED_CORE 203
> +#define SOF_TKN_SCHED_FRAMES 204
> +#define SOF_TKN_SCHED_TIMER 205
> +
> +/* volume */
> +#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250
> +#define SOF_TKN_VOLUME_RAMP_STEP_MS 251
> +
> +/* SRC */
> +#define SOF_TKN_SRC_RATE_IN 300
> +#define SOF_TKN_SRC_RATE_OUT 301
> +
> +/* Generic components */
> +#define SOF_TKN_COMP_PERIOD_SINK_COUNT 400
> +#define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401
> +#define SOF_TKN_COMP_FORMAT 402
> +#define SOF_TKN_COMP_PRELOAD_COUNT 403
> +
> +struct comp_info {
> + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
> + int id;
> + int type;
> + int pipeline_id;
> +};
> +
> +struct frame_types {
> + char *name;
> + enum sof_ipc_frame frame;
> +};
> +
> +static const struct frame_types sof_frames[] = {
> + {"s16le", SOF_IPC_FRAME_S16_LE},
> + {"s24le", SOF_IPC_FRAME_S24_4LE},
> + {"s32le", SOF_IPC_FRAME_S32_LE},
> + {"float", SOF_IPC_FRAME_FLOAT},
> +};
> +
> +struct sof_topology_token {
> + uint32_t token;
> + uint32_t type;
> + int (*get_token)(void *elem, void *object, uint32_t offset,
> + uint32_t size);
> + uint32_t offset;
> + uint32_t size;
> +};
> +
> +enum sof_ipc_frame find_format(const char *name);
> +
> +int get_token_uint32_t(void *elem, void *object, uint32_t offset,
> + uint32_t size);
> +
> +int get_token_comp_format(void *elem, void *object, uint32_t offset,
> + uint32_t size);
> +
> +/* Buffers */
> +static const struct sof_topology_token buffer_tokens[] = {
> + {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
> + offsetof(struct sof_ipc_buffer, size), 0},
> + {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
> + offsetof(struct sof_ipc_buffer, caps), 0},
> +};
> +
> +/* scheduling */
> +static const struct sof_topology_token sched_tokens[] = {
> + {SOF_TKN_SCHED_DEADLINE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_pipe_new, deadline), 0},
> + {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_pipe_new, priority), 0},
> + {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_pipe_new, mips), 0},
> + {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_pipe_new, core), 0},
> + {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0},
> + {SOF_TKN_SCHED_TIMER, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_pipe_new, timer), 0},
> +};
> +
> +/* volume */
> +static const struct sof_topology_token volume_tokens[] = {
> + {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_volume, ramp), 0},
> + {SOF_TKN_VOLUME_RAMP_STEP_MS,
> + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_volume, initial_ramp), 0},
> +};
> +
> +/* SRC */
> +static const struct sof_topology_token src_tokens[] = {
> + {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_src, source_rate), 0},
> + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD,
> + get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_src, sink_rate), 0},
> +};
> +
> +/* Tone */
> +static const struct sof_topology_token tone_tokens[] = {
> +};
> +
> +/* Generic components */
> +static const struct sof_topology_token comp_tokens[] = {
> + {SOF_TKN_COMP_PERIOD_SINK_COUNT,
> + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_config, periods_sink), 0},
> + {SOF_TKN_COMP_PERIOD_SOURCE_COUNT,
> + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_config, periods_source), 0},
> + {SOF_TKN_COMP_FORMAT,
> + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
> + offsetof(struct sof_ipc_comp_config, frame_fmt), 0},
> + {SOF_TKN_COMP_PRELOAD_COUNT,
> + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
> + offsetof(struct sof_ipc_comp_config, preload_count), 0},
> +};
> +
> +int sof_parse_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array,
> + int priv_size);
> +void sof_parse_string_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array);
> +void sof_parse_uuid_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array);
> +void sof_parse_word_tokens(void *object,
> + const struct sof_topology_token *tokens,
> + int count,
> + struct snd_soc_tplg_vendor_array *array);
> +
> +int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id,
> + int *sched_id, char *bits_in,
> + char *in_file, char *out_file);
> +
> +#endif
More information about the Sound-open-firmware
mailing list