xref: /linux-6.15/sound/soc/sof/compress.c (revision 2dc51106)
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 <[email protected]>
9 //
10 
11 #include <sound/soc.h>
12 #include "compress.h"
13 #include "ops.h"
14 #include "probe.h"
15 
16 static int sof_probe_compr_open(struct snd_compr_stream *cstream,
17 				struct snd_soc_dai *dai)
18 {
19 	struct snd_sof_dev *sdev =
20 				snd_soc_component_get_drvdata(dai->component);
21 	int ret;
22 
23 	ret = snd_sof_probe_compr_assign(sdev, cstream, dai);
24 	if (ret < 0) {
25 		dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret);
26 		return ret;
27 	}
28 
29 	sdev->extractor_stream_tag = ret;
30 	return 0;
31 }
32 
33 static int sof_probe_compr_free(struct snd_compr_stream *cstream,
34 				struct snd_soc_dai *dai)
35 {
36 	struct snd_sof_dev *sdev =
37 				snd_soc_component_get_drvdata(dai->component);
38 	struct sof_probe_point_desc *desc;
39 	size_t num_desc;
40 	int i, ret;
41 
42 	/* disconnect all probe points */
43 	ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc);
44 	if (ret < 0) {
45 		dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
46 		goto exit;
47 	}
48 
49 	for (i = 0; i < num_desc; i++)
50 		sof_ipc_probe_points_remove(sdev, &desc[i].buffer_id, 1);
51 	kfree(desc);
52 
53 exit:
54 	ret = sof_ipc_probe_deinit(sdev);
55 	if (ret < 0)
56 		dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
57 
58 	sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
59 	snd_compr_free_pages(cstream);
60 
61 	return snd_sof_probe_compr_free(sdev, cstream, dai);
62 }
63 
64 static int sof_probe_compr_set_params(struct snd_compr_stream *cstream,
65 				      struct snd_compr_params *params,
66 				      struct snd_soc_dai *dai)
67 {
68 	struct snd_compr_runtime *rtd = cstream->runtime;
69 	struct snd_sof_dev *sdev =
70 				snd_soc_component_get_drvdata(dai->component);
71 	int ret;
72 
73 	cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
74 	cstream->dma_buffer.dev.dev = sdev->dev;
75 	ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
76 	if (ret < 0)
77 		return ret;
78 
79 	ret = snd_sof_probe_compr_set_params(sdev, cstream, params, dai);
80 	if (ret < 0)
81 		return ret;
82 
83 	ret = sof_ipc_probe_init(sdev, sdev->extractor_stream_tag,
84 				 rtd->dma_bytes);
85 	if (ret < 0) {
86 		dev_err(dai->dev, "Failed to init probe: %d\n", ret);
87 		return ret;
88 	}
89 
90 	return 0;
91 }
92 
93 static int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
94 				   struct snd_soc_dai *dai)
95 {
96 	struct snd_sof_dev *sdev =
97 				snd_soc_component_get_drvdata(dai->component);
98 
99 	return snd_sof_probe_compr_trigger(sdev, cstream, cmd, dai);
100 }
101 
102 static int sof_probe_compr_pointer(struct snd_compr_stream *cstream,
103 				   struct snd_compr_tstamp *tstamp,
104 				   struct snd_soc_dai *dai)
105 {
106 	struct snd_sof_dev *sdev =
107 				snd_soc_component_get_drvdata(dai->component);
108 
109 	return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai);
110 }
111 
112 struct snd_soc_cdai_ops sof_probe_compr_ops = {
113 	.startup	= sof_probe_compr_open,
114 	.shutdown	= sof_probe_compr_free,
115 	.set_params	= sof_probe_compr_set_params,
116 	.trigger	= sof_probe_compr_trigger,
117 	.pointer	= sof_probe_compr_pointer,
118 };
119 EXPORT_SYMBOL(sof_probe_compr_ops);
120 
121 static int sof_probe_compr_copy(struct snd_soc_component *component,
122 				struct snd_compr_stream *cstream,
123 				char __user *buf, size_t count)
124 {
125 	struct snd_compr_runtime *rtd = cstream->runtime;
126 	unsigned int offset, n;
127 	void *ptr;
128 	int ret;
129 
130 	if (count > rtd->buffer_size)
131 		count = rtd->buffer_size;
132 
133 	div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
134 	ptr = rtd->dma_area + offset;
135 	n = rtd->buffer_size - offset;
136 
137 	if (count < n) {
138 		ret = copy_to_user(buf, ptr, count);
139 	} else {
140 		ret = copy_to_user(buf, ptr, n);
141 		ret += copy_to_user(buf + n, rtd->dma_area, count - n);
142 	}
143 
144 	if (ret)
145 		return count - ret;
146 	return count;
147 }
148 
149 const struct snd_compress_ops sof_probe_compressed_ops = {
150 	.copy		= sof_probe_compr_copy,
151 };
152 EXPORT_SYMBOL(sof_probe_compressed_ops);
153