mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
ASoC: SOF: Convert the generic probe support to SOF client
Add a new client driver for probes support and move all the probes-related code from the core to the client driver. The probes client driver registers a component driver with one CPU DAI driver for extraction and creates a new sound card with one DUMMY DAI link with a dummy codec that will be used for extracting audio data from specific points in the audio pipeline. The probes debugfs ops are based on the initial implementation by Cezary Rojewski and have been moved out of the SOF core into the client driver making it easier to maintain. This change will make it easier for the probes functionality to be added for all platforms without having the need to modify the existing(15+) machine drivers. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Link: https://lore.kernel.org/r/20220210150525.30756-10-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
@@ -53,13 +53,14 @@ config SND_SOC_SOF_COMPRESS
|
||||
select SND_SOC_COMPRESS
|
||||
|
||||
config SND_SOC_SOF_DEBUG_PROBES
|
||||
bool "SOF enable data probing"
|
||||
tristate
|
||||
select SND_SOC_SOF_CLIENT
|
||||
select SND_SOC_COMPRESS
|
||||
help
|
||||
This option enables the data probing feature that can be used to
|
||||
gather data directly from specific points of the audio pipeline.
|
||||
Say Y if you want to enable probes.
|
||||
If unsure, select "N".
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level.
|
||||
|
||||
config SND_SOC_SOF_CLIENT
|
||||
tristate
|
||||
|
||||
@@ -4,7 +4,6 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
|
||||
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
|
||||
snd-sof-$(CONFIG_SND_SOC_SOF_CLIENT) += sof-client.o
|
||||
|
||||
snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o
|
||||
snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o
|
||||
|
||||
snd-sof-pci-objs := sof-pci-dev.o
|
||||
@@ -13,6 +12,7 @@ snd-sof-of-objs := sof-of-dev.o
|
||||
|
||||
snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o
|
||||
snd-sof-ipc-msg-injector-objs := sof-client-ipc-msg-injector.o
|
||||
snd-sof-probes-objs := sof-client-probes.o
|
||||
|
||||
snd-sof-nocodec-objs := nocodec.o
|
||||
|
||||
@@ -29,6 +29,7 @@ obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) += snd-sof-ipc-flood-test.o
|
||||
obj-$(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) += snd-sof-ipc-msg-injector.o
|
||||
obj-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += snd-sof-probes.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/
|
||||
obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
#include <sound/sof.h>
|
||||
#include "sof-priv.h"
|
||||
#include "ops.h"
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
#include "sof-probes.h"
|
||||
#endif
|
||||
|
||||
/* see SOF_DBG_ flags */
|
||||
static int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE);
|
||||
@@ -358,9 +355,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
|
||||
|
||||
sdev->pdata = plat_data;
|
||||
sdev->first_boot = true;
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
|
||||
#endif
|
||||
dev_set_drvdata(dev, sdev);
|
||||
|
||||
/* check all mandatory ops */
|
||||
|
||||
@@ -19,221 +19,6 @@
|
||||
#include "sof-priv.h"
|
||||
#include "ops.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
#include "sof-probes.h"
|
||||
|
||||
/**
|
||||
* strsplit_u32 - Split string into sequence of u32 tokens
|
||||
* @buf: String to split into tokens.
|
||||
* @delim: String containing delimiter characters.
|
||||
* @tkns: Returned u32 sequence pointer.
|
||||
* @num_tkns: Returned number of tokens obtained.
|
||||
*/
|
||||
static int
|
||||
strsplit_u32(char **buf, const char *delim, u32 **tkns, size_t *num_tkns)
|
||||
{
|
||||
char *s;
|
||||
u32 *data, *tmp;
|
||||
size_t count = 0;
|
||||
size_t cap = 32;
|
||||
int ret = 0;
|
||||
|
||||
*tkns = NULL;
|
||||
*num_tkns = 0;
|
||||
data = kcalloc(cap, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
while ((s = strsep(buf, delim)) != NULL) {
|
||||
ret = kstrtouint(s, 0, data + count);
|
||||
if (ret)
|
||||
goto exit;
|
||||
if (++count >= cap) {
|
||||
cap *= 2;
|
||||
tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL);
|
||||
if (!tmp) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
data = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (!count)
|
||||
goto exit;
|
||||
*tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL);
|
||||
if (*tkns == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
*num_tkns = count;
|
||||
|
||||
exit:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tokenize_input(const char __user *from, size_t count,
|
||||
loff_t *ppos, u32 **tkns, size_t *num_tkns)
|
||||
{
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
buf = kmalloc(count + 1, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = simple_write_to_buffer(buf, count, ppos, from, count);
|
||||
if (ret != count) {
|
||||
ret = ret >= 0 ? -EIO : ret;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
buf[count] = '\0';
|
||||
ret = strsplit_u32((char **)&buf, ",", tkns, num_tkns);
|
||||
exit:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t probe_points_read(struct file *file,
|
||||
char __user *to, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct snd_sof_dfsentry *dfse = file->private_data;
|
||||
struct snd_sof_dev *sdev = dfse->sdev;
|
||||
struct sof_probe_point_desc *desc;
|
||||
size_t num_desc, len = 0;
|
||||
char *buf;
|
||||
int i, ret;
|
||||
|
||||
if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
|
||||
dev_warn(sdev->dev, "no extractor stream running\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
for (i = 0; i < num_desc; i++) {
|
||||
ret = snprintf(buf + len, PAGE_SIZE - len,
|
||||
"Id: %#010x Purpose: %d Node id: %#x\n",
|
||||
desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
|
||||
if (ret < 0)
|
||||
goto free_desc;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
ret = simple_read_from_buffer(to, count, ppos, buf, len);
|
||||
free_desc:
|
||||
kfree(desc);
|
||||
exit:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t probe_points_write(struct file *file,
|
||||
const char __user *from, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct snd_sof_dfsentry *dfse = file->private_data;
|
||||
struct snd_sof_dev *sdev = dfse->sdev;
|
||||
struct sof_probe_point_desc *desc;
|
||||
size_t num_tkns, bytes;
|
||||
u32 *tkns;
|
||||
int ret;
|
||||
|
||||
if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
|
||||
dev_warn(sdev->dev, "no extractor stream running\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
bytes = sizeof(*tkns) * num_tkns;
|
||||
if (!num_tkns || (bytes % sizeof(*desc))) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
desc = (struct sof_probe_point_desc *)tkns;
|
||||
ret = sof_ipc_probe_points_add(sdev,
|
||||
desc, bytes / sizeof(*desc));
|
||||
if (!ret)
|
||||
ret = count;
|
||||
exit:
|
||||
kfree(tkns);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations probe_points_fops = {
|
||||
.open = simple_open,
|
||||
.read = probe_points_read,
|
||||
.write = probe_points_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t probe_points_remove_write(struct file *file,
|
||||
const char __user *from, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct snd_sof_dfsentry *dfse = file->private_data;
|
||||
struct snd_sof_dev *sdev = dfse->sdev;
|
||||
size_t num_tkns;
|
||||
u32 *tkns;
|
||||
int ret;
|
||||
|
||||
if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
|
||||
dev_warn(sdev->dev, "no extractor stream running\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!num_tkns) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = sof_ipc_probe_points_remove(sdev, tkns, num_tkns);
|
||||
if (!ret)
|
||||
ret = count;
|
||||
exit:
|
||||
kfree(tkns);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations probe_points_remove_fops = {
|
||||
.open = simple_open,
|
||||
.write = probe_points_remove_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev,
|
||||
const char *name, mode_t mode,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
struct snd_sof_dfsentry *dfse;
|
||||
|
||||
dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
|
||||
if (!dfse)
|
||||
return -ENOMEM;
|
||||
|
||||
dfse->type = SOF_DFSENTRY_TYPE_BUF;
|
||||
dfse->sdev = sdev;
|
||||
|
||||
debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops);
|
||||
/* add to dfsentry list */
|
||||
list_add(&dfse->list, &sdev->dfsentry_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@@ -569,17 +354,6 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
err = snd_sof_debugfs_probe_item(sdev, "probe_points",
|
||||
0644, &probe_points_fops);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_sof_debugfs_probe_item(sdev, "probe_points_remove",
|
||||
0200, &probe_points_remove_fops);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
|
||||
|
||||
@@ -215,6 +215,7 @@ config SND_SOC_SOF_HDA_COMMON
|
||||
select SND_SOC_SOF_PCI_DEV
|
||||
select SND_INTEL_DSP_CONFIG
|
||||
select SND_SOC_SOF_HDA_LINK_BASELINE
|
||||
select SND_SOC_SOF_HDA_PROBES
|
||||
help
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level.
|
||||
@@ -240,15 +241,6 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
|
||||
Say Y if you want to enable HDAudio codecs with SOF.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_SOF_HDA_PROBES
|
||||
bool "SOF enable probes over HDA"
|
||||
depends on SND_SOC_SOF_DEBUG_PROBES
|
||||
help
|
||||
This option enables the data probing for Intel(R)
|
||||
Skylake and newer platforms.
|
||||
Say Y if you want to enable probes.
|
||||
If unsure, select "N".
|
||||
|
||||
endif ## SND_SOC_SOF_HDA_COMMON
|
||||
|
||||
config SND_SOC_SOF_HDA_LINK_BASELINE
|
||||
@@ -266,6 +258,15 @@ config SND_SOC_SOF_HDA
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level.
|
||||
|
||||
config SND_SOC_SOF_HDA_PROBES
|
||||
bool
|
||||
select SND_SOC_SOF_DEBUG_PROBES
|
||||
help
|
||||
The option enables the data probing for Intel(R) Skylake and newer
|
||||
(HDA) platforms.
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level.
|
||||
|
||||
config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
|
||||
tristate
|
||||
select SOUNDWIRE_INTEL if SND_SOC_SOF_INTEL_SOUNDWIRE
|
||||
|
||||
@@ -80,15 +80,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
|
||||
.pcm_pointer = hda_dsp_pcm_pointer,
|
||||
.pcm_ack = hda_dsp_pcm_ack,
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
/* probe callbacks */
|
||||
.probe_assign = hda_probe_compr_assign,
|
||||
.probe_free = hda_probe_compr_free,
|
||||
.probe_set_params = hda_probe_compr_set_params,
|
||||
.probe_trigger = hda_probe_compr_trigger,
|
||||
.probe_pointer = hda_probe_compr_pointer,
|
||||
#endif
|
||||
|
||||
/* firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_raw,
|
||||
|
||||
@@ -110,6 +101,10 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
|
||||
.trace_release = hda_dsp_trace_release,
|
||||
.trace_trigger = hda_dsp_trace_trigger,
|
||||
|
||||
/* client ops */
|
||||
.register_ipc_clients = hda_register_clients,
|
||||
.unregister_ipc_clients = hda_unregister_clients,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = skl_dai,
|
||||
.num_drv = SOF_SKL_NUM_DAIS,
|
||||
|
||||
@@ -298,15 +298,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
|
||||
.pcm_pointer = hda_dsp_pcm_pointer,
|
||||
.pcm_ack = hda_dsp_pcm_ack,
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
/* probe callbacks */
|
||||
.probe_assign = hda_probe_compr_assign,
|
||||
.probe_free = hda_probe_compr_free,
|
||||
.probe_set_params = hda_probe_compr_set_params,
|
||||
.probe_trigger = hda_probe_compr_trigger,
|
||||
.probe_pointer = hda_probe_compr_pointer,
|
||||
#endif
|
||||
|
||||
/* firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_raw,
|
||||
|
||||
@@ -328,6 +319,10 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
|
||||
.trace_release = hda_dsp_trace_release,
|
||||
.trace_trigger = hda_dsp_trace_trigger,
|
||||
|
||||
/* client ops */
|
||||
.register_ipc_clients = hda_register_clients,
|
||||
.unregister_ipc_clients = hda_unregister_clients,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = skl_dai,
|
||||
.num_drv = SOF_SKL_NUM_DAIS,
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
#include "../sof-probes.h"
|
||||
#endif
|
||||
|
||||
struct hda_pipe_params {
|
||||
u32 ch;
|
||||
u32 s_freq;
|
||||
@@ -737,20 +733,5 @@ struct snd_soc_dai_driver skl_dai[] = {
|
||||
.channels_max = 16,
|
||||
},
|
||||
},
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
{
|
||||
.name = "Probe Extraction CPU DAI",
|
||||
.compress_new = snd_soc_new_compress,
|
||||
.cops = &sof_probe_compr_ops,
|
||||
.capture = {
|
||||
.stream_name = "Probe Extraction",
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2019-2020 Intel Corporation. All rights reserved.
|
||||
// Copyright(c) 2019-2021 Intel Corporation. All rights reserved.
|
||||
//
|
||||
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||
// Converted to SOF client:
|
||||
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
// Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
|
||||
//
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include <sound/soc.h>
|
||||
#include "../sof-priv.h"
|
||||
#include "../sof-client-probes.h"
|
||||
#include "../sof-client.h"
|
||||
#include "hda.h"
|
||||
|
||||
static inline struct hdac_ext_stream *
|
||||
@@ -19,10 +25,11 @@ hda_compr_get_stream(struct snd_compr_stream *cstream)
|
||||
return cstream->runtime->private_data;
|
||||
}
|
||||
|
||||
int hda_probe_compr_assign(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
static int hda_probes_compr_assign(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai, u32 *stream_id)
|
||||
{
|
||||
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
|
||||
struct hdac_ext_stream *hext_stream;
|
||||
|
||||
hext_stream = hda_dsp_stream_get(sdev, cstream->direction, 0);
|
||||
@@ -33,14 +40,17 @@ int hda_probe_compr_assign(struct snd_sof_dev *sdev,
|
||||
hdac_stream(hext_stream)->cstream = cstream;
|
||||
cstream->runtime->private_data = hext_stream;
|
||||
|
||||
return hdac_stream(hext_stream)->stream_tag;
|
||||
*stream_id = hdac_stream(hext_stream)->stream_tag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hda_probe_compr_free(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
static int hda_probes_compr_free(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
|
||||
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
|
||||
int ret;
|
||||
|
||||
ret = hda_dsp_stream_put(sdev, cstream->direction,
|
||||
@@ -56,12 +66,13 @@ int hda_probe_compr_free(struct snd_sof_dev *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hda_probe_compr_set_params(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
static int hda_probes_compr_set_params(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
|
||||
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
|
||||
struct hdac_stream *hstream = hdac_stream(hext_stream);
|
||||
struct snd_dma_buffer *dmab;
|
||||
u32 bits, rate;
|
||||
@@ -89,19 +100,20 @@ int hda_probe_compr_set_params(struct snd_sof_dev *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hda_probe_compr_trigger(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
static int hda_probes_compr_trigger(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
|
||||
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
|
||||
|
||||
return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
|
||||
}
|
||||
|
||||
int hda_probe_compr_pointer(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp,
|
||||
struct snd_soc_dai *dai)
|
||||
static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
|
||||
struct snd_soc_pcm_stream *pstream;
|
||||
@@ -112,3 +124,25 @@ int hda_probe_compr_pointer(struct snd_sof_dev *sdev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SOF client implementation */
|
||||
static const struct sof_probes_host_ops hda_probes_ops = {
|
||||
.assign = hda_probes_compr_assign,
|
||||
.free = hda_probes_compr_free,
|
||||
.set_params = hda_probes_compr_set_params,
|
||||
.trigger = hda_probes_compr_trigger,
|
||||
.pointer = hda_probes_compr_pointer,
|
||||
};
|
||||
|
||||
int hda_probes_register(struct snd_sof_dev *sdev)
|
||||
{
|
||||
return sof_client_dev_register(sdev, "hda-probes", 0, &hda_probes_ops,
|
||||
sizeof(hda_probes_ops));
|
||||
}
|
||||
|
||||
void hda_probes_unregister(struct snd_sof_dev *sdev)
|
||||
{
|
||||
sof_client_dev_unregister(sdev, "hda-probes", 0);
|
||||
}
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
|
||||
|
||||
@@ -1423,6 +1423,16 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
|
||||
}
|
||||
EXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_COMMON);
|
||||
|
||||
int hda_register_clients(struct snd_sof_dev *sdev)
|
||||
{
|
||||
return hda_probes_register(sdev);
|
||||
}
|
||||
|
||||
void hda_unregister_clients(struct snd_sof_dev *sdev)
|
||||
{
|
||||
hda_probes_unregister(sdev);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC);
|
||||
|
||||
+20
-29
@@ -16,6 +16,7 @@
|
||||
#include <sound/compress_driver.h>
|
||||
#include <sound/hda_codec.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include "../sof-client-probes.h"
|
||||
#include "shim.h"
|
||||
|
||||
/* PCI registers */
|
||||
@@ -351,13 +352,7 @@
|
||||
|
||||
/* Number of DAIs */
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
#define SOF_SKL_NUM_DAIS 16
|
||||
#else
|
||||
#define SOF_SKL_NUM_DAIS 15
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SOF_SKL_NUM_DAIS 8
|
||||
#endif
|
||||
@@ -575,29 +570,6 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream,
|
||||
const struct sof_ipc_pcm_params_reply *reply);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
/*
|
||||
* Probe Compress Operations.
|
||||
*/
|
||||
int hda_probe_compr_assign(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai);
|
||||
int hda_probe_compr_free(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai);
|
||||
int hda_probe_compr_set_params(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
int hda_probe_compr_trigger(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream, int cmd,
|
||||
struct snd_soc_dai *dai);
|
||||
int hda_probe_compr_pointer(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp,
|
||||
struct snd_soc_dai *dai);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DSP IPC Operations.
|
||||
*/
|
||||
@@ -729,6 +701,25 @@ extern const struct sof_intel_dsp_desc ehl_chip_info;
|
||||
extern const struct sof_intel_dsp_desc jsl_chip_info;
|
||||
extern const struct sof_intel_dsp_desc adls_chip_info;
|
||||
|
||||
/* Probes support */
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
int hda_probes_register(struct snd_sof_dev *sdev);
|
||||
void hda_probes_unregister(struct snd_sof_dev *sdev);
|
||||
#else
|
||||
static inline int hda_probes_register(struct snd_sof_dev *sdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void hda_probes_unregister(struct snd_sof_dev *sdev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_SND_SOC_SOF_HDA_PROBES */
|
||||
|
||||
/* SOF client registration for HDA platforms */
|
||||
int hda_register_clients(struct snd_sof_dev *sdev);
|
||||
void hda_unregister_clients(struct snd_sof_dev *sdev);
|
||||
|
||||
/* machine driver select */
|
||||
struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev);
|
||||
void hda_set_mach_params(struct snd_soc_acpi_mach *mach,
|
||||
|
||||
@@ -142,15 +142,6 @@ const struct snd_sof_dsp_ops sof_icl_ops = {
|
||||
.pcm_pointer = hda_dsp_pcm_pointer,
|
||||
.pcm_ack = hda_dsp_pcm_ack,
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
/* probe callbacks */
|
||||
.probe_assign = hda_probe_compr_assign,
|
||||
.probe_free = hda_probe_compr_free,
|
||||
.probe_set_params = hda_probe_compr_set_params,
|
||||
.probe_trigger = hda_probe_compr_trigger,
|
||||
.probe_pointer = hda_probe_compr_pointer,
|
||||
#endif
|
||||
|
||||
/* firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_raw,
|
||||
|
||||
@@ -173,6 +164,10 @@ const struct snd_sof_dsp_ops sof_icl_ops = {
|
||||
.trace_release = hda_dsp_trace_release,
|
||||
.trace_trigger = hda_dsp_trace_trigger,
|
||||
|
||||
/* client ops */
|
||||
.register_ipc_clients = hda_register_clients,
|
||||
.unregister_ipc_clients = hda_unregister_clients,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = skl_dai,
|
||||
.num_drv = SOF_SKL_NUM_DAIS,
|
||||
|
||||
@@ -115,15 +115,6 @@ const struct snd_sof_dsp_ops sof_tgl_ops = {
|
||||
.pcm_pointer = hda_dsp_pcm_pointer,
|
||||
.pcm_ack = hda_dsp_pcm_ack,
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
|
||||
/* probe callbacks */
|
||||
.probe_assign = hda_probe_compr_assign,
|
||||
.probe_free = hda_probe_compr_free,
|
||||
.probe_set_params = hda_probe_compr_set_params,
|
||||
.probe_trigger = hda_probe_compr_trigger,
|
||||
.probe_pointer = hda_probe_compr_pointer,
|
||||
#endif
|
||||
|
||||
/* firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_raw,
|
||||
|
||||
@@ -146,6 +137,10 @@ const struct snd_sof_dsp_ops sof_tgl_ops = {
|
||||
.trace_release = hda_dsp_trace_release,
|
||||
.trace_trigger = hda_dsp_trace_trigger,
|
||||
|
||||
/* client ops */
|
||||
.register_ipc_clients = hda_register_clients,
|
||||
.unregister_ipc_clients = hda_unregister_clients,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = skl_dai,
|
||||
.num_drv = SOF_SKL_NUM_DAIS,
|
||||
|
||||
@@ -497,49 +497,6 @@ static inline int snd_sof_pcm_platform_ack(struct snd_sof_dev *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
static inline int
|
||||
snd_sof_probe_compr_assign(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
|
||||
{
|
||||
return sof_ops(sdev)->probe_assign(sdev, cstream, dai);
|
||||
}
|
||||
|
||||
static inline int
|
||||
snd_sof_probe_compr_free(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
|
||||
{
|
||||
return sof_ops(sdev)->probe_free(sdev, cstream, dai);
|
||||
}
|
||||
|
||||
static inline int
|
||||
snd_sof_probe_compr_set_params(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
return sof_ops(sdev)->probe_set_params(sdev, cstream, params, dai);
|
||||
}
|
||||
|
||||
static inline int
|
||||
snd_sof_probe_compr_trigger(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
return sof_ops(sdev)->probe_trigger(sdev, cstream, cmd, dai);
|
||||
}
|
||||
|
||||
static inline int
|
||||
snd_sof_probe_compr_pointer(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
|
||||
{
|
||||
if (sof_ops(sdev) && sof_ops(sdev)->probe_pointer)
|
||||
return sof_ops(sdev)->probe_pointer(sdev, cstream, tstamp, dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* machine driver */
|
||||
static inline int
|
||||
snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
|
||||
|
||||
+1
-7
@@ -15,11 +15,8 @@
|
||||
#include <sound/sof.h>
|
||||
#include "sof-priv.h"
|
||||
#include "sof-audio.h"
|
||||
#include "ops.h"
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
#include "sof-probes.h"
|
||||
#endif
|
||||
#include "sof-utils.h"
|
||||
#include "ops.h"
|
||||
|
||||
/* Create DMA buffer page table for DSP */
|
||||
static int create_page_table(struct snd_soc_component *component,
|
||||
@@ -925,9 +922,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
|
||||
pd->pointer = sof_pcm_pointer;
|
||||
pd->ack = sof_pcm_ack;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
pd->compress_ops = &sof_probe_compressed_ops;
|
||||
#endif
|
||||
pd->pcm_construct = sof_pcm_new;
|
||||
pd->ignore_machine = drv_name;
|
||||
pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef __SOF_CLIENT_PROBES_H
|
||||
#define __SOF_CLIENT_PROBES_H
|
||||
|
||||
struct snd_compr_stream;
|
||||
struct snd_compr_tstamp;
|
||||
struct snd_compr_params;
|
||||
struct sof_client_dev;
|
||||
struct snd_soc_dai;
|
||||
|
||||
/*
|
||||
* Callbacks used on platforms where the control for audio is split between
|
||||
* DSP and host, like HDA.
|
||||
*/
|
||||
struct sof_probes_host_ops {
|
||||
int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai, u32 *stream_id);
|
||||
int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai);
|
||||
int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
int (*trigger)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
int cmd, struct snd_soc_dai *dai);
|
||||
int (*pointer)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp,
|
||||
struct snd_soc_dai *dai);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -201,27 +201,6 @@ struct snd_sof_dsp_ops {
|
||||
/* pcm ack */
|
||||
int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
/* Except for probe_pointer, all probe ops are mandatory */
|
||||
int (*probe_assign)(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai); /* mandatory */
|
||||
int (*probe_free)(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai); /* mandatory */
|
||||
int (*probe_set_params)(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai); /* mandatory */
|
||||
int (*probe_trigger)(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream, int cmd,
|
||||
struct snd_soc_dai *dai); /* mandatory */
|
||||
int (*probe_pointer)(struct snd_sof_dev *sdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp,
|
||||
struct snd_soc_dai *dai); /* optional */
|
||||
#endif
|
||||
|
||||
/* host read DSP stream data */
|
||||
int (*ipc_msg_data)(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream,
|
||||
@@ -446,10 +425,6 @@ struct snd_sof_dev {
|
||||
int ipc_timeout;
|
||||
int boot_timeout;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
|
||||
unsigned int extractor_stream_tag;
|
||||
#endif
|
||||
|
||||
/* DMA for Trace */
|
||||
struct snd_dma_buffer dmatb;
|
||||
struct snd_dma_buffer dmatp;
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2019-2021 Intel Corporation. All rights reserved.
|
||||
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||
//
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include "ops.h"
|
||||
#include "sof-priv.h"
|
||||
#include "sof-probes.h"
|
||||
|
||||
struct sof_probe_dma {
|
||||
unsigned int stream_tag;
|
||||
unsigned int dma_buffer_size;
|
||||
} __packed;
|
||||
|
||||
struct sof_ipc_probe_dma_add_params {
|
||||
struct sof_ipc_cmd_hdr hdr;
|
||||
unsigned int num_elems;
|
||||
struct sof_probe_dma dma[];
|
||||
} __packed;
|
||||
|
||||
struct sof_ipc_probe_info_params {
|
||||
struct sof_ipc_reply rhdr;
|
||||
unsigned int num_elems;
|
||||
union {
|
||||
struct sof_probe_dma dma[0];
|
||||
struct sof_probe_point_desc desc[0];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct sof_ipc_probe_point_add_params {
|
||||
struct sof_ipc_cmd_hdr hdr;
|
||||
unsigned int num_elems;
|
||||
struct sof_probe_point_desc desc[];
|
||||
} __packed;
|
||||
|
||||
struct sof_ipc_probe_point_remove_params {
|
||||
struct sof_ipc_cmd_hdr hdr;
|
||||
unsigned int num_elems;
|
||||
unsigned int buffer_id[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* sof_ipc_probe_init - initialize data probing
|
||||
* @sdev: SOF sound device
|
||||
* @stream_tag: Extractor stream tag
|
||||
* @buffer_size: DMA buffer size to set for extractor
|
||||
*
|
||||
* Host chooses whether extraction is supported or not by providing
|
||||
* valid stream tag to DSP. Once specified, stream described by that
|
||||
* tag will be tied to DSP for extraction for the entire lifetime of
|
||||
* probe.
|
||||
*
|
||||
* Probing is initialized only once and each INIT request must be
|
||||
* matched by DEINIT call.
|
||||
*/
|
||||
static int sof_ipc_probe_init(struct snd_sof_dev *sdev, u32 stream_tag,
|
||||
size_t buffer_size)
|
||||
{
|
||||
struct sof_ipc_probe_dma_add_params *msg;
|
||||
struct sof_ipc_reply reply;
|
||||
size_t size = struct_size(msg, dma, 1);
|
||||
int ret;
|
||||
|
||||
msg = kmalloc(size, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
msg->hdr.size = size;
|
||||
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
|
||||
msg->num_elems = 1;
|
||||
msg->dma[0].stream_tag = stream_tag;
|
||||
msg->dma[0].dma_buffer_size = buffer_size;
|
||||
|
||||
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
|
||||
&reply, sizeof(reply));
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sof_ipc_probe_deinit - cleanup after data probing
|
||||
* @sdev: SOF sound device
|
||||
*
|
||||
* Host sends DEINIT request to free previously initialized probe
|
||||
* on DSP side once it is no longer needed. DEINIT only when there
|
||||
* are no probes connected and with all injectors detached.
|
||||
*/
|
||||
static int sof_ipc_probe_deinit(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct sof_ipc_cmd_hdr msg;
|
||||
struct sof_ipc_reply reply;
|
||||
|
||||
msg.size = sizeof(msg);
|
||||
msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
|
||||
|
||||
return sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size,
|
||||
&reply, sizeof(reply));
|
||||
}
|
||||
|
||||
static int sof_ipc_probe_info(struct snd_sof_dev *sdev, unsigned int cmd,
|
||||
void **params, size_t *num_params)
|
||||
{
|
||||
struct sof_ipc_probe_info_params msg = {{{0}}};
|
||||
struct sof_ipc_probe_info_params *reply;
|
||||
size_t bytes;
|
||||
int ret;
|
||||
|
||||
*params = NULL;
|
||||
*num_params = 0;
|
||||
|
||||
reply = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
|
||||
if (!reply)
|
||||
return -ENOMEM;
|
||||
msg.rhdr.hdr.size = sizeof(msg);
|
||||
msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
|
||||
|
||||
ret = sof_ipc_tx_message(sdev->ipc, msg.rhdr.hdr.cmd, &msg,
|
||||
msg.rhdr.hdr.size, reply, SOF_IPC_MSG_MAX_SIZE);
|
||||
if (ret < 0 || reply->rhdr.error < 0)
|
||||
goto exit;
|
||||
|
||||
if (!reply->num_elems)
|
||||
goto exit;
|
||||
|
||||
if (cmd == SOF_IPC_PROBE_DMA_INFO)
|
||||
bytes = sizeof(reply->dma[0]);
|
||||
else
|
||||
bytes = sizeof(reply->desc[0]);
|
||||
bytes *= reply->num_elems;
|
||||
*params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
|
||||
if (!*params) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
*num_params = reply->num_elems;
|
||||
|
||||
exit:
|
||||
kfree(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sof_ipc_probe_points_info - retrieve list of active probe points
|
||||
* @sdev: SOF sound device
|
||||
* @desc: Returned list of active probes
|
||||
* @num_desc: Returned count of active probes
|
||||
*
|
||||
* Host sends PROBE_POINT_INFO request to obtain list of active probe
|
||||
* points, valid for disconnection when given probe is no longer
|
||||
* required.
|
||||
*/
|
||||
int sof_ipc_probe_points_info(struct snd_sof_dev *sdev,
|
||||
struct sof_probe_point_desc **desc,
|
||||
size_t *num_desc)
|
||||
{
|
||||
return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_POINT_INFO,
|
||||
(void **)desc, num_desc);
|
||||
}
|
||||
EXPORT_SYMBOL(sof_ipc_probe_points_info);
|
||||
|
||||
/**
|
||||
* sof_ipc_probe_points_add - connect specified probes
|
||||
* @sdev: SOF sound device
|
||||
* @desc: List of probe points to connect
|
||||
* @num_desc: Number of elements in @desc
|
||||
*
|
||||
* Dynamically connects to provided set of endpoints. Immediately
|
||||
* after connection is established, host must be prepared to
|
||||
* transfer data from or to target stream given the probing purpose.
|
||||
*
|
||||
* Each probe point should be removed using PROBE_POINT_REMOVE
|
||||
* request when no longer needed.
|
||||
*/
|
||||
int sof_ipc_probe_points_add(struct snd_sof_dev *sdev,
|
||||
struct sof_probe_point_desc *desc, size_t num_desc)
|
||||
{
|
||||
struct sof_ipc_probe_point_add_params *msg;
|
||||
struct sof_ipc_reply reply;
|
||||
size_t size = struct_size(msg, desc, num_desc);
|
||||
int ret;
|
||||
|
||||
msg = kmalloc(size, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
msg->hdr.size = size;
|
||||
msg->num_elems = num_desc;
|
||||
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
|
||||
memcpy(&msg->desc[0], desc, size - sizeof(*msg));
|
||||
|
||||
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
|
||||
&reply, sizeof(reply));
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(sof_ipc_probe_points_add);
|
||||
|
||||
/**
|
||||
* sof_ipc_probe_points_remove - disconnect specified probes
|
||||
* @sdev: SOF sound device
|
||||
* @buffer_id: List of probe points to disconnect
|
||||
* @num_buffer_id: Number of elements in @desc
|
||||
*
|
||||
* Removes previously connected probes from list of active probe
|
||||
* points and frees all resources on DSP side.
|
||||
*/
|
||||
int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev,
|
||||
unsigned int *buffer_id, size_t num_buffer_id)
|
||||
{
|
||||
struct sof_ipc_probe_point_remove_params *msg;
|
||||
struct sof_ipc_reply reply;
|
||||
size_t size = struct_size(msg, buffer_id, num_buffer_id);
|
||||
int ret;
|
||||
|
||||
msg = kmalloc(size, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
msg->hdr.size = size;
|
||||
msg->num_elems = num_buffer_id;
|
||||
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
|
||||
memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
|
||||
|
||||
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
|
||||
&reply, sizeof(reply));
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(sof_ipc_probe_points_remove);
|
||||
|
||||
static int sof_probe_compr_startup(struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
int ret;
|
||||
|
||||
ret = snd_sof_probe_compr_assign(sdev, cstream, dai);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdev->extractor_stream_tag = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_probe_compr_shutdown(struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
struct sof_probe_point_desc *desc;
|
||||
size_t num_desc;
|
||||
int i, ret;
|
||||
|
||||
/* disconnect all probe points */
|
||||
ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_desc; i++)
|
||||
sof_ipc_probe_points_remove(sdev, &desc[i].buffer_id, 1);
|
||||
kfree(desc);
|
||||
|
||||
exit:
|
||||
ret = sof_ipc_probe_deinit(sdev);
|
||||
if (ret < 0)
|
||||
dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
|
||||
|
||||
sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
|
||||
snd_compr_free_pages(cstream);
|
||||
|
||||
return snd_sof_probe_compr_free(sdev, cstream, dai);
|
||||
}
|
||||
|
||||
static int sof_probe_compr_set_params(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
struct snd_compr_runtime *rtd = cstream->runtime;
|
||||
int ret;
|
||||
|
||||
cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
|
||||
cstream->dma_buffer.dev.dev = sdev->dev;
|
||||
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_sof_probe_compr_set_params(sdev, cstream, params, dai);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sof_ipc_probe_init(sdev, sdev->extractor_stream_tag,
|
||||
rtd->dma_bytes);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "Failed to init probe: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
|
||||
return snd_sof_probe_compr_trigger(sdev, cstream, cmd, dai);
|
||||
}
|
||||
|
||||
static int sof_probe_compr_pointer(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
|
||||
return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai);
|
||||
}
|
||||
|
||||
const struct snd_soc_cdai_ops sof_probe_compr_ops = {
|
||||
.startup = sof_probe_compr_startup,
|
||||
.shutdown = sof_probe_compr_shutdown,
|
||||
.set_params = sof_probe_compr_set_params,
|
||||
.trigger = sof_probe_compr_trigger,
|
||||
.pointer = sof_probe_compr_pointer,
|
||||
};
|
||||
EXPORT_SYMBOL(sof_probe_compr_ops);
|
||||
|
||||
static int sof_probe_compr_copy(struct snd_soc_component *component,
|
||||
struct snd_compr_stream *cstream,
|
||||
char __user *buf, size_t count)
|
||||
{
|
||||
struct snd_compr_runtime *rtd = cstream->runtime;
|
||||
unsigned int offset, n;
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
if (count > rtd->buffer_size)
|
||||
count = rtd->buffer_size;
|
||||
|
||||
div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
|
||||
ptr = rtd->dma_area + offset;
|
||||
n = rtd->buffer_size - offset;
|
||||
|
||||
if (count < n) {
|
||||
ret = copy_to_user(buf, ptr, count);
|
||||
} else {
|
||||
ret = copy_to_user(buf, ptr, n);
|
||||
ret += copy_to_user(buf + n, rtd->dma_area, count - n);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return count - ret;
|
||||
return count;
|
||||
}
|
||||
|
||||
const struct snd_compress_ops sof_probe_compressed_ops = {
|
||||
.copy = sof_probe_compr_copy,
|
||||
};
|
||||
EXPORT_SYMBOL(sof_probe_compressed_ops);
|
||||
@@ -1,38 +0,0 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* Copyright(c) 2019-2021 Intel Corporation. All rights reserved.
|
||||
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __SOF_PROBES_H
|
||||
#define __SOF_PROBES_H
|
||||
|
||||
#include <sound/compress_driver.h>
|
||||
#include <sound/sof/header.h>
|
||||
|
||||
struct snd_sof_dev;
|
||||
|
||||
#define SOF_PROBE_INVALID_NODE_ID UINT_MAX
|
||||
|
||||
struct sof_probe_point_desc {
|
||||
unsigned int buffer_id;
|
||||
unsigned int purpose;
|
||||
unsigned int stream_tag;
|
||||
} __packed;
|
||||
|
||||
int sof_ipc_probe_points_info(struct snd_sof_dev *sdev,
|
||||
struct sof_probe_point_desc **desc,
|
||||
size_t *num_desc);
|
||||
int sof_ipc_probe_points_add(struct snd_sof_dev *sdev,
|
||||
struct sof_probe_point_desc *desc,
|
||||
size_t num_desc);
|
||||
int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev,
|
||||
unsigned int *buffer_id, size_t num_buffer_id);
|
||||
|
||||
extern const struct snd_soc_cdai_ops sof_probe_compr_ops;
|
||||
extern const struct snd_compress_ops sof_probe_compressed_ops;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user