diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 53626f45419d..dfa145ad566d 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -115,6 +115,9 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) list(APPEND base_files host-legacy.c) sof_list_append_ifdef(CONFIG_COMP_DAI base_files dai-legacy.c) endif() + if(CONFIG_COMP_TEMPLATE_COMP) + add_subdirectory(template_comp) + endif() endif() ### Common files (also used in shared library build) diff --git a/src/audio/Kconfig b/src/audio/Kconfig index d0be938077df..f76a99c2335e 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -164,6 +164,8 @@ rsource "mfcc/Kconfig" rsource "codec/Kconfig" +rsource "template_comp/Kconfig" + endmenu # "Audio components" menu "Data formats" diff --git a/src/audio/template_comp/CMakeLists.txt b/src/audio/template_comp/CMakeLists.txt new file mode 100644 index 000000000000..d21be2f9ab88 --- /dev/null +++ b/src/audio/template_comp/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_TEMPLATE_COMP STREQUAL "m") + add_subdirectory(llext ${PROJECT_BINARY_DIR}/template_comp_llext) + add_dependencies(app template_comp) +else() + add_local_sources(sof template.c) + add_local_sources(sof template-generic.c) + + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof template-ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof template-ipc4.c) + endif() +endif() diff --git a/src/audio/template_comp/Kconfig b/src/audio/template_comp/Kconfig new file mode 100644 index 000000000000..29d385cbbe98 --- /dev/null +++ b/src/audio/template_comp/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_TEMPLATE_COMP + tristate "Template_comp example component" + default y + help + Select for template_comp component. Reason for existence + is to provide a minimal component example and use as + placeholder in processing pipelines. As example processing + it swaps or reverses the channels when the switch control + is enabled. diff --git a/src/audio/template_comp/llext/CMakeLists.txt b/src/audio/template_comp/llext/CMakeLists.txt new file mode 100644 index 000000000000..9e97d91f28fc --- /dev/null +++ b/src/audio/template_comp/llext/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("template_comp" + SOURCES ../template_comp.c + LIB openmodules +) diff --git a/src/audio/template_comp/llext/llext.toml.h b/src/audio/template_comp/llext/llext.toml.h new file mode 100644 index 000000000000..4808c9af8f42 --- /dev/null +++ b/src/audio/template_comp/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include +#define LOAD_TYPE "2" +#include "../template_comp.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/template_comp/template-generic.c b/src/audio/template_comp/template-generic.c new file mode 100644 index 000000000000..39617e667b90 --- /dev/null +++ b/src/audio/template_comp/template-generic.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include "template.h" + +#if CONFIG_FORMAT_S16LE +/** + * template_comp_s16() - Process S16_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 16-bit signed integer PCM formats. The + * audio samples in every frame are re-order to channels order defined in + * component data channel_map[]. + * + * Return: Value zero for success, otherwise an error code. + */ +static int template_comp_s16(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct template_comp_comp_data *cd = module_get_private_data(mod); + int16_t *x, *x_start, *x_end; + int16_t *y, *y_start, *y_end; + size_t size; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int ch; + int i; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s16 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data(source, bytes, (void const **)&x, (void const **)&x_start, &size); + if (ret) + return ret; + + x_size = size >> 1; /* Bytes to number of s16 samples */ + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer(sink, bytes, (void **)&y, (void **)&y_start, &size); + if (ret) + return ret; + + y_size = size >> 1; /* Bytes to number of s16 samples */ + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, samples); + + /* Since the example processing is for frames of audio channels, process + * with step of channels count. + */ + for (i = 0; i < samples_without_wrap; i += cd->channels) { + /* In inner loop process the frame. As example re-arrange the channels + * as defined in array channel_map[]. + */ + for (ch = 0; ch < cd->channels; ch++) { + *y = *(x + cd->channel_map[ch]); + y++; + } + x += cd->channels; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S32LE +/** + * template_comp_s32() - Process S32_LE or S24_4LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * Processing function for signed integer 32-bit PCM formats. The same + * function works for s24 and s32 formats since the samples values are + * not modified in computation. The audio samples in every frame are + * re-order to channels order defined in component data channel_map[]. + * + * Return: Value zero for success, otherwise an error code. + */ +static int template_comp_s32(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct template_comp_comp_data *cd = module_get_private_data(mod); + int32_t *x, *x_start, *x_end; + int32_t *y, *y_start, *y_end; + size_t size; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int ch; + int i; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s16 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data(source, bytes, (void const **)&x, (void const **)&x_start, &size); + if (ret) + return ret; + + x_size = size >> 2; /* Bytes to number of s32 samples */ + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer(sink, bytes, (void **)&y, (void **)&y_start, &size); + if (ret) + return ret; + + y_size = size >> 2; /* Bytes to number of s32 samples */ + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, samples); + + /* Since the example processing is for frames of audio channels, process + * with step of channels count. + */ + for (i = 0; i < samples_without_wrap; i += cd->channels) { + /* In inner loop process the frame. As example re-arrange the channels + * as defined in array channel_map[]. + */ + for (ch = 0; ch < cd->channels; ch++) { + *y = *(x + cd->channel_map[ch]); + y++; + } + x += cd->channels; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct template_comp_proc_fnmap template_comp_proc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, template_comp_s16 }, +#endif +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, template_comp_s32 }, +#endif +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, template_comp_s32 }, +#endif +}; + +/** + * template_comp_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +template_comp_func template_comp_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(template_comp_proc_fnmap); i++) + if (src_fmt == template_comp_proc_fnmap[i].frame_fmt) + return template_comp_proc_fnmap[i].template_comp_proc_func; + + return NULL; +} diff --git a/src/audio/template_comp/template-ipc3.c b/src/audio/template_comp/template-ipc3.c new file mode 100644 index 000000000000..757afb8bf923 --- /dev/null +++ b/src/audio/template_comp/template-ipc3.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include +#include +#include "template.h" + +LOG_MODULE_DECLARE(template_comp, CONFIG_SOF_LOG_LEVEL); + +/* This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + */ +__cold int template_comp_set_config(struct processing_module *mod, uint32_t param_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, uint8_t *response, + size_t response_size) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct template_comp_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + comp_dbg(dev, "template_comp_set_config()"); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_SWITCH: + if (cdata->index != 0) { + comp_err(dev, "Illegal switch control index = %d.", cdata->index); + return -EINVAL; + } + + if (cdata->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", cdata->num_elems); + return -EINVAL; + } + + cd->enable = cdata->chanv[0].value; + comp_info(dev, "Setting enable = %d.", cd->enable); + return 0; + + case SOF_CTRL_CMD_ENUM: + comp_err(dev, "Illegal enum control, no support in this component."); + return -EINVAL; + case SOF_CTRL_CMD_BINARY: + comp_err(dev, "Illegal bytes control, no support in this component."); + return -EINVAL; + } + + comp_err(dev, "Illegal control, unknown type."); + return -EINVAL; +} + +__cold int template_comp_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct template_comp_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + comp_info(dev, "template_comp_get_config()"); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_SWITCH: + if (cdata->index != 0) { + comp_err(dev, "Illegal switch control index = %d.", cdata->index); + return -EINVAL; + } + + if (cdata->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", cdata->num_elems); + return -EINVAL; + } + + cdata->chanv[0].value = cd->enable; + return 0; + + case SOF_CTRL_CMD_ENUM: + comp_err(dev, "Illegal enum control, no support in this component."); + return -EINVAL; + + case SOF_CTRL_CMD_BINARY: + comp_err(dev, "Illegal bytes control, no support in this component."); + return -EINVAL; + } + + comp_err(dev, "Illegal control, unknown type."); + return -EINVAL; +} diff --git a/src/audio/template_comp/template-ipc4.c b/src/audio/template_comp/template-ipc4.c new file mode 100644 index 000000000000..e11a6695ef9d --- /dev/null +++ b/src/audio/template_comp/template-ipc4.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include +#include +#include "template.h" + +LOG_MODULE_DECLARE(template_comp, CONFIG_SOF_LOG_LEVEL); + +/* IPC4 controls handler */ +__cold int template_comp_set_config(struct processing_module *mod, + uint32_t param_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, + const uint8_t *fragment, + size_t fragment_size, + uint8_t *response, + size_t response_size) +{ + struct sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; + struct template_comp_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + comp_dbg(dev, "Switch control id = %d, num_elems = %d.", ctl->id, ctl->num_elems); + if (ctl->id != 0) { + comp_err(dev, "Illegal switch control id = %d.", ctl->id); + return -EINVAL; + } + + if (ctl->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", ctl->num_elems); + return -EINVAL; + } + + cd->enable = ctl->chanv[0].value; + comp_info(dev, "Setting enable = %d.", cd->enable); + return 0; + + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_err(dev, "Illegal enum control, no support in this component."); + return -EINVAL; + } + + comp_err(mod->dev, "Illegal bytes control, no support in this component."); + return -EINVAL; +} + +/* Not used in IPC4 systems, if IPC4 only component, omit .get_configuration set */ +__cold int template_comp_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + assert_can_be_cold(); + return 0; +} diff --git a/src/audio/template_comp/template.c b/src/audio/template_comp/template.c new file mode 100644 index 000000000000..06f702645531 --- /dev/null +++ b/src/audio/template_comp/template.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include +#include +#include +#include +#include +#include "template.h" + +/* UUID identifies the components. Use e.g. command uuidgen from package + * uuid-runtime, add it to uuid-registry.txt in SOF top level. + */ +SOF_DEFINE_REG_UUID(template_comp); + +/* Creates logging data for the component */ +LOG_MODULE_REGISTER(template_comp, CONFIG_SOF_LOG_LEVEL); + +/* Creates the compont trace. Traces show in trace console the component + * info, warning, and error messages. + */ +DECLARE_TR_CTX(template_comp_tr, SOF_UUID(template_comp_uuid), LOG_LEVEL_INFO); + +/** + * template_comp_init() - Initialize the template component. + * @mod: Pointer to module data. + * + * This function is called when the instance is created. The + * macro __cold informs that the code that is non-critical + * is loaded to slower but large DRAM. + * + * Return: Zero if success, otherwise error code. + */ +__cold static int template_comp_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct template_comp_comp_data *cd; + + comp_info(dev, "template_comp_init()"); + + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + return 0; +} + +/** + * template_comp_process() - The audio data processing function. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * This is the processing function that is called for scheduled + * pipelines. The processing is controlled by the enable switch. + * + * Return: Zero if success, otherwise error code. + */ +static int template_comp_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + struct template_comp_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct sof_source *source = sources[0]; + struct sof_sink *sink = sinks[0]; + int frames = source_get_data_frames_available(source); + int sink_frames = sink_get_free_frames(sink); + + comp_dbg(dev, "template_comp_process()"); + + frames = MIN(frames, sink_frames); + if (cd->enable) + /* Process the data with the channels swap example function. */ + return cd->template_comp_func(mod, source, sink, frames); + + /* Just copy from source to sink. */ + source_to_sink_copy(source, sink, true, frames * cd->frame_bytes); + return 0; +} + +/** + * template_comp_prepare() - Prepare the component for processing. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * Function prepare is called just before the pipeline is started. In + * this case the audio format parameters are for better code performance + * saved to component data to avoid to find out them in process. The + * processing function pointer is set to process the current audio format. + * + * Return: Value zero if success, otherwise error code. + */ +static int template_comp_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct template_comp_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + enum sof_ipc_frame source_format; + int i; + + comp_dbg(dev, "template_comp_prepare()"); + + if (num_of_sources != 1 || num_of_sinks != 1) + return -EINVAL; + + /* get source data format */ + cd->frame_bytes = source_get_frame_bytes(sources[0]); + cd->channels = source_get_channels(sources[0]); + source_format = source_get_frm_fmt(sources[0]); + + /* Initialize channels order for reversing */ + for (i = 0; i < cd->channels; i++) + cd->channel_map[i] = cd->channels - i - 1; + + cd->template_comp_func = template_comp_find_proc_func(source_format); + if (!cd->template_comp_func) { + comp_err(dev, "No processing function found for format %d.", + source_format); + return -EINVAL; + } + + return 0; +} + +/** + * template_comp_reset() - Reset the component. + * @mod: Pointer to module data. + * + * The component reset is called when pipeline is stopped. The reset + * should return the component to same state as init. + * + * Return: Value zero, always success. + */ +static int template_comp_reset(struct processing_module *mod) +{ + struct template_comp_comp_data *cd = module_get_private_data(mod); + + comp_dbg(mod->dev, "template_comp_reset()"); + memset(cd, 0, sizeof(*cd)); + return 0; +} + +/** + * template_comp_free() - Free dynamic allocations. + * @mod: Pointer to module data. + * + * Component free is called when the pipelines are deleted. All + * dynamic allocations need to be freed here. The macro __cold + * instructs the build to locate this performance wise non-critical + * function to large and slower DRAM. + * + * Return: Value zero, always success. + */ +__cold static int template_comp_free(struct processing_module *mod) +{ + struct template_comp_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + + comp_dbg(mod->dev, "template_comp_free()"); + rfree(cd); + return 0; +} + +/* This defines the module operations */ +static const struct module_interface template_comp_interface = { + .init = template_comp_init, + .prepare = template_comp_prepare, + .process = template_comp_process, + .set_configuration = template_comp_set_config, + .get_configuration = template_comp_get_config, + .reset = template_comp_reset, + .free = template_comp_free +}; + +/* This controls build of the module. If COMP_MODULE is selected in kconfig + * this is build as dynamically loadable module. + */ +#if CONFIG_COMP_TEMPLATE_COMP_MODULE + +#include +#include +#include + +SOF_LLEXT_MOD_ENTRY(template_comp, &template_comp_interface); + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("TEMPLATE", template_comp_llext_entry, 1, + SOF_REG_UUID(template_comp), 40); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_MODULE_ADAPTER(template_comp_interface, template_comp_uuid, template_comp_tr); +SOF_MODULE_INIT(template_comp, sys_comp_module_template_comp_interface_init); + +#endif diff --git a/src/audio/template_comp/template.h b/src/audio/template_comp/template.h new file mode 100644 index 000000000000..667d95702c10 --- /dev/null +++ b/src/audio/template_comp/template.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ +#ifndef __SOF_AUDIO_TEMPLATE_COMP_H__ +#define __SOF_AUDIO_TEMPLATE_COMP_H__ + +#include +#include +#include + +/** + * struct template_comp_func - Function call pointer for process function + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + */ +typedef int (*template_comp_func)(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); + +/* Template_Comp component private data */ + +/** + * struct template_comp_comp_data + * @template_comp_func: Pointer to used processing function. + * @channels_order[]: Vector with desired sink channels order. + * @source_format: Source samples format. + * @frame_bytes: Number of bytes in an audio frame. + * @channels: Channels count. + * @enable: Control processing on/off, on - reorder channels + */ +struct template_comp_comp_data { + template_comp_func template_comp_func; + int channel_map[PLATFORM_MAX_CHANNELS]; + int source_format; + int frame_bytes; + int channels; + bool enable; +}; + +/** + * struct template_comp_proc_fnmap - processing functions for frame formats + * @frame_fmt: Current frame format + * @template_comp_proc_func: Function pointer for the suitable processing function + */ +struct template_comp_proc_fnmap { + enum sof_ipc_frame frame_fmt; + template_comp_func template_comp_proc_func; +}; + +/** + * template_comp_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +template_comp_func template_comp_find_proc_func(enum sof_ipc_frame src_fmt); + +/** + * template_comp_set_config() - Handle controls set + * @mod: Pointer to module data. + * @param_id: Id to know control type, used to know ALSA control type. + * @pos: Position of the fragment in the large message. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * @response_size: Size of response. + * + * This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + * + * Return: Zero if success, otherwise error code. + */ +int template_comp_set_config(struct processing_module *mod, + uint32_t param_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, + const uint8_t *fragment, + size_t fragment_size, + uint8_t *response, + size_t response_size); + +/** + * template_comp_set_config() - Handle controls get + * @mod: Pointer to module data. + * @config_id: Configuration ID. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * + * This function is used for controls get. + * + * Return: Zero if success, otherwise error code. + */ +int template_comp_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size); + +#endif // __SOF_AUDIO_TEMPLATE_COMP_H__ diff --git a/src/audio/template_comp/template_comp.toml b/src/audio/template_comp/template_comp.toml new file mode 100644 index 000000000000..c4d28b125fe3 --- /dev/null +++ b/src/audio/template_comp/template_comp.toml @@ -0,0 +1,21 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Template component module config + [[module.entry]] + name = "TEMPLATE" + uuid = UUIDREG_STR_TEMPLATE_COMP + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + index = __COUNTER__ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index b6976973b5c9..acfb12607aab 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -900,6 +900,7 @@ void sys_comp_module_selector_interface_init(void); void sys_comp_module_src_interface_init(void); void sys_comp_module_src_lite_interface_init(void); void sys_comp_module_tdfb_interface_init(void); +void sys_comp_module_template_comp_interface_init(void); void sys_comp_module_volume_interface_init(void); void sys_comp_module_tester_interface_init(void); diff --git a/tools/rimage/config/lnl.toml.h b/tools/rimage/config/lnl.toml.h index 90ac20abbace..6d1e0f0ef04a 100644 --- a/tools/rimage/config/lnl.toml.h +++ b/tools/rimage/config/lnl.toml.h @@ -134,5 +134,9 @@ #include