6
6
// Amadeusz Slawinski <[email protected] >
7
7
//
8
8
9
+ #include <sound/compress_driver.h>
10
+ #include <sound/hdaudio_ext.h>
11
+ #include <sound/hdaudio.h>
12
+ #include <sound/soc.h>
9
13
#include "avs.h"
10
14
#include "messages.h"
11
15
12
- __maybe_unused
13
16
static int avs_dsp_init_probe (struct avs_dev * adev , union avs_connector_node_id node_id ,
14
17
size_t buffer_size )
15
-
16
18
{
17
19
struct avs_probe_cfg cfg = {{0 }};
18
20
struct avs_module_entry mentry ;
@@ -34,7 +36,6 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id
34
36
sizeof (cfg ), & dummy );
35
37
}
36
38
37
- __maybe_unused
38
39
static void avs_dsp_delete_probe (struct avs_dev * adev )
39
40
{
40
41
struct avs_module_entry mentry ;
@@ -44,3 +45,220 @@ static void avs_dsp_delete_probe(struct avs_dev *adev)
44
45
/* There is only ever one probe module instance. */
45
46
avs_dsp_delete_module (adev , mentry .module_id , 0 , INVALID_PIPELINE_ID , 0 );
46
47
}
48
+
49
+ static inline struct hdac_ext_stream * avs_compr_get_host_stream (struct snd_compr_stream * cstream )
50
+ {
51
+ return cstream -> runtime -> private_data ;
52
+ }
53
+
54
+ static int avs_probe_compr_open (struct snd_compr_stream * cstream , struct snd_soc_dai * dai )
55
+ {
56
+ struct avs_dev * adev = to_avs_dev (dai -> dev );
57
+ struct hdac_bus * bus = & adev -> base .core ;
58
+ struct hdac_ext_stream * host_stream ;
59
+
60
+ if (adev -> extractor ) {
61
+ dev_err (dai -> dev , "Cannot open more than one extractor stream\n" );
62
+ return - EEXIST ;
63
+ }
64
+
65
+ host_stream = snd_hdac_ext_cstream_assign (bus , cstream );
66
+ if (!host_stream ) {
67
+ dev_err (dai -> dev , "Failed to assign HDAudio stream for extraction\n" );
68
+ return - EBUSY ;
69
+ }
70
+
71
+ adev -> extractor = host_stream ;
72
+ hdac_stream (host_stream )-> curr_pos = 0 ;
73
+ cstream -> runtime -> private_data = host_stream ;
74
+
75
+ return 0 ;
76
+ }
77
+
78
+ static int avs_probe_compr_free (struct snd_compr_stream * cstream , struct snd_soc_dai * dai )
79
+ {
80
+ struct hdac_ext_stream * host_stream = avs_compr_get_host_stream (cstream );
81
+ struct avs_dev * adev = to_avs_dev (dai -> dev );
82
+ struct avs_probe_point_desc * desc ;
83
+ /* Extractor node identifier. */
84
+ unsigned int vindex = INVALID_NODE_ID .vindex ;
85
+ size_t num_desc ;
86
+ int i , ret ;
87
+
88
+ /* Disconnect all probe points. */
89
+ ret = avs_ipc_probe_get_points (adev , & desc , & num_desc );
90
+ if (ret ) {
91
+ dev_err (dai -> dev , "get probe points failed: %d\n" , ret );
92
+ ret = AVS_IPC_RET (ret );
93
+ goto exit ;
94
+ }
95
+
96
+ for (i = 0 ; i < num_desc ; i ++ )
97
+ if (desc [i ].node_id .vindex == vindex )
98
+ avs_ipc_probe_disconnect_points (adev , & desc [i ].id , 1 );
99
+ kfree (desc );
100
+
101
+ exit :
102
+ if (adev -> num_probe_streams ) {
103
+ adev -> num_probe_streams -- ;
104
+ if (!adev -> num_probe_streams ) {
105
+ avs_dsp_delete_probe (adev );
106
+ avs_dsp_enable_d0ix (adev );
107
+ }
108
+ }
109
+
110
+ snd_hdac_stream_cleanup (hdac_stream (host_stream ));
111
+ hdac_stream (host_stream )-> prepared = 0 ;
112
+ snd_hdac_ext_stream_release (host_stream , HDAC_EXT_STREAM_TYPE_HOST );
113
+
114
+ snd_compr_free_pages (cstream );
115
+ adev -> extractor = NULL ;
116
+
117
+ return ret ;
118
+ }
119
+
120
+ static int avs_probe_compr_set_params (struct snd_compr_stream * cstream ,
121
+ struct snd_compr_params * params , struct snd_soc_dai * dai )
122
+ {
123
+ struct hdac_ext_stream * host_stream = avs_compr_get_host_stream (cstream );
124
+ struct snd_compr_runtime * rtd = cstream -> runtime ;
125
+ struct avs_dev * adev = to_avs_dev (dai -> dev );
126
+ /* compr params do not store bit depth, default to S32_LE. */
127
+ snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE ;
128
+ unsigned int format_val ;
129
+ int bps , ret ;
130
+
131
+ hdac_stream (host_stream )-> bufsize = 0 ;
132
+ hdac_stream (host_stream )-> period_bytes = 0 ;
133
+ hdac_stream (host_stream )-> format_val = 0 ;
134
+ cstream -> dma_buffer .dev .type = SNDRV_DMA_TYPE_DEV_SG ;
135
+ cstream -> dma_buffer .dev .dev = adev -> dev ;
136
+
137
+ ret = snd_compr_malloc_pages (cstream , rtd -> buffer_size );
138
+ if (ret < 0 )
139
+ return ret ;
140
+ bps = snd_pcm_format_physical_width (format );
141
+ if (bps < 0 )
142
+ return bps ;
143
+ format_val = snd_hdac_calc_stream_format (params -> codec .sample_rate , params -> codec .ch_out ,
144
+ format , bps , 0 );
145
+ ret = snd_hdac_stream_set_params (hdac_stream (host_stream ), format_val );
146
+ if (ret < 0 )
147
+ return ret ;
148
+ ret = snd_hdac_stream_setup (hdac_stream (host_stream ));
149
+ if (ret < 0 )
150
+ return ret ;
151
+
152
+ hdac_stream (host_stream )-> prepared = 1 ;
153
+
154
+ if (!adev -> num_probe_streams ) {
155
+ union avs_connector_node_id node_id ;
156
+
157
+ /* D0ix not allowed during probing. */
158
+ ret = avs_dsp_disable_d0ix (adev );
159
+ if (ret )
160
+ return ret ;
161
+
162
+ node_id .vindex = hdac_stream (host_stream )-> stream_tag - 1 ;
163
+ node_id .dma_type = AVS_DMA_HDA_HOST_INPUT ;
164
+
165
+ ret = avs_dsp_init_probe (adev , node_id , rtd -> dma_bytes );
166
+ if (ret < 0 ) {
167
+ dev_err (dai -> dev , "probe init failed: %d\n" , ret );
168
+ avs_dsp_enable_d0ix (adev );
169
+ return ret ;
170
+ }
171
+ }
172
+
173
+ adev -> num_probe_streams ++ ;
174
+ return 0 ;
175
+ }
176
+
177
+ static int avs_probe_compr_trigger (struct snd_compr_stream * cstream , int cmd ,
178
+ struct snd_soc_dai * dai )
179
+ {
180
+ struct hdac_ext_stream * host_stream = avs_compr_get_host_stream (cstream );
181
+ struct avs_dev * adev = to_avs_dev (dai -> dev );
182
+ struct hdac_bus * bus = & adev -> base .core ;
183
+ unsigned long cookie ;
184
+
185
+ if (!hdac_stream (host_stream )-> prepared )
186
+ return - EPIPE ;
187
+
188
+ switch (cmd ) {
189
+ case SNDRV_PCM_TRIGGER_START :
190
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
191
+ case SNDRV_PCM_TRIGGER_RESUME :
192
+ spin_lock_irqsave (& bus -> reg_lock , cookie );
193
+ snd_hdac_stream_start (hdac_stream (host_stream ), true);
194
+ spin_unlock_irqrestore (& bus -> reg_lock , cookie );
195
+ break ;
196
+
197
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
198
+ case SNDRV_PCM_TRIGGER_SUSPEND :
199
+ case SNDRV_PCM_TRIGGER_STOP :
200
+ spin_lock_irqsave (& bus -> reg_lock , cookie );
201
+ snd_hdac_stream_stop (hdac_stream (host_stream ));
202
+ spin_unlock_irqrestore (& bus -> reg_lock , cookie );
203
+ break ;
204
+
205
+ default :
206
+ return - EINVAL ;
207
+ }
208
+
209
+ return 0 ;
210
+ }
211
+
212
+ static int avs_probe_compr_pointer (struct snd_compr_stream * cstream ,
213
+ struct snd_compr_tstamp * tstamp , struct snd_soc_dai * dai )
214
+ {
215
+ struct hdac_ext_stream * host_stream = avs_compr_get_host_stream (cstream );
216
+ struct snd_soc_pcm_stream * pstream ;
217
+
218
+ pstream = & dai -> driver -> capture ;
219
+ tstamp -> copied_total = hdac_stream (host_stream )-> curr_pos ;
220
+ tstamp -> sampling_rate = snd_pcm_rate_bit_to_rate (pstream -> rates );
221
+
222
+ return 0 ;
223
+ }
224
+
225
+ static int avs_probe_compr_copy (struct snd_soc_component * comp , struct snd_compr_stream * cstream ,
226
+ char __user * buf , size_t count )
227
+ {
228
+ struct snd_compr_runtime * rtd = cstream -> runtime ;
229
+ unsigned int offset , n ;
230
+ void * ptr ;
231
+ int ret ;
232
+
233
+ if (count > rtd -> buffer_size )
234
+ count = rtd -> buffer_size ;
235
+
236
+ div_u64_rem (rtd -> total_bytes_transferred , rtd -> buffer_size , & offset );
237
+ ptr = rtd -> dma_area + offset ;
238
+ n = rtd -> buffer_size - offset ;
239
+
240
+ if (count < n ) {
241
+ ret = copy_to_user (buf , ptr , count );
242
+ } else {
243
+ ret = copy_to_user (buf , ptr , n );
244
+ ret += copy_to_user (buf + n , rtd -> dma_area , count - n );
245
+ }
246
+
247
+ if (ret )
248
+ return count - ret ;
249
+ return count ;
250
+ }
251
+
252
+ __maybe_unused
253
+ static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
254
+ .startup = avs_probe_compr_open ,
255
+ .shutdown = avs_probe_compr_free ,
256
+ .set_params = avs_probe_compr_set_params ,
257
+ .trigger = avs_probe_compr_trigger ,
258
+ .pointer = avs_probe_compr_pointer ,
259
+ };
260
+
261
+ __maybe_unused
262
+ static const struct snd_compress_ops avs_probe_compress_ops = {
263
+ .copy = avs_probe_compr_copy ,
264
+ };
0 commit comments