xref: /kernel/linux/linux-5.10/sound/soc/sof/compress.c (revision 8c2ecf20)
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license.  When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2019-2020 Intel Corporation. All rights reserved.
7//
8// Author: Cezary Rojewski <cezary.rojewski@intel.com>
9//
10
11#include <sound/soc.h>
12#include "compress.h"
13#include "ops.h"
14#include "probe.h"
15
16struct snd_compress_ops sof_probe_compressed_ops = {
17	.copy		= sof_probe_compr_copy,
18};
19EXPORT_SYMBOL(sof_probe_compressed_ops);
20
21int sof_probe_compr_open(struct snd_compr_stream *cstream,
22		struct snd_soc_dai *dai)
23{
24	struct snd_sof_dev *sdev =
25				snd_soc_component_get_drvdata(dai->component);
26	int ret;
27
28	ret = snd_sof_probe_compr_assign(sdev, cstream, dai);
29	if (ret < 0) {
30		dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret);
31		return ret;
32	}
33
34	sdev->extractor_stream_tag = ret;
35	return 0;
36}
37EXPORT_SYMBOL(sof_probe_compr_open);
38
39int sof_probe_compr_free(struct snd_compr_stream *cstream,
40		struct snd_soc_dai *dai)
41{
42	struct snd_sof_dev *sdev =
43				snd_soc_component_get_drvdata(dai->component);
44	struct sof_probe_point_desc *desc;
45	size_t num_desc;
46	int i, ret;
47
48	/* disconnect all probe points */
49	ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc);
50	if (ret < 0) {
51		dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
52		goto exit;
53	}
54
55	for (i = 0; i < num_desc; i++)
56		sof_ipc_probe_points_remove(sdev, &desc[i].buffer_id, 1);
57	kfree(desc);
58
59exit:
60	ret = sof_ipc_probe_deinit(sdev);
61	if (ret < 0)
62		dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
63
64	sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
65	snd_compr_free_pages(cstream);
66
67	return snd_sof_probe_compr_free(sdev, cstream, dai);
68}
69EXPORT_SYMBOL(sof_probe_compr_free);
70
71int sof_probe_compr_set_params(struct snd_compr_stream *cstream,
72		struct snd_compr_params *params, struct snd_soc_dai *dai)
73{
74	struct snd_compr_runtime *rtd = cstream->runtime;
75	struct snd_sof_dev *sdev =
76				snd_soc_component_get_drvdata(dai->component);
77	int ret;
78
79	cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
80	cstream->dma_buffer.dev.dev = sdev->dev;
81	ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
82	if (ret < 0)
83		return ret;
84
85	ret = snd_sof_probe_compr_set_params(sdev, cstream, params, dai);
86	if (ret < 0)
87		return ret;
88
89	ret = sof_ipc_probe_init(sdev, sdev->extractor_stream_tag,
90				 rtd->dma_bytes);
91	if (ret < 0) {
92		dev_err(dai->dev, "Failed to init probe: %d\n", ret);
93		return ret;
94	}
95
96	return 0;
97}
98EXPORT_SYMBOL(sof_probe_compr_set_params);
99
100int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
101		struct snd_soc_dai *dai)
102{
103	struct snd_sof_dev *sdev =
104				snd_soc_component_get_drvdata(dai->component);
105
106	return snd_sof_probe_compr_trigger(sdev, cstream, cmd, dai);
107}
108EXPORT_SYMBOL(sof_probe_compr_trigger);
109
110int sof_probe_compr_pointer(struct snd_compr_stream *cstream,
111		struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
112{
113	struct snd_sof_dev *sdev =
114				snd_soc_component_get_drvdata(dai->component);
115
116	return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai);
117}
118EXPORT_SYMBOL(sof_probe_compr_pointer);
119
120int sof_probe_compr_copy(struct snd_soc_component *component,
121			 struct snd_compr_stream *cstream,
122			 char __user *buf, size_t count)
123{
124	struct snd_compr_runtime *rtd = cstream->runtime;
125	unsigned int offset, n;
126	void *ptr;
127	int ret;
128
129	if (count > rtd->buffer_size)
130		count = rtd->buffer_size;
131
132	div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
133	ptr = rtd->dma_area + offset;
134	n = rtd->buffer_size - offset;
135
136	if (count < n) {
137		ret = copy_to_user(buf, ptr, count);
138	} else {
139		ret = copy_to_user(buf, ptr, n);
140		ret += copy_to_user(buf + n, rtd->dma_area, count - n);
141	}
142
143	if (ret)
144		return count - ret;
145	return count;
146}
147EXPORT_SYMBOL(sof_probe_compr_copy);
148