~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/avs/probes.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 //
  3 // Copyright(c) 2021-2022 Intel Corporation
  4 //
  5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
  6 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
  7 //
  8 
  9 #include <sound/compress_driver.h>
 10 #include <sound/hdaudio_ext.h>
 11 #include <sound/hdaudio.h>
 12 #include <sound/soc.h>
 13 #include "avs.h"
 14 #include "messages.h"
 15 
 16 static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
 17                               size_t buffer_size)
 18 {
 19         struct avs_probe_cfg cfg = {{0}};
 20         struct avs_module_entry mentry;
 21         u8 dummy;
 22         int ret;
 23 
 24         ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
 25         if (ret)
 26                 return ret;
 27 
 28         /*
 29          * Probe module uses no cycles, audio data format and input and output
 30          * frame sizes are unused. It is also not owned by any pipeline.
 31          */
 32         cfg.base.ibs = 1;
 33         /* BSS module descriptor is always segment of index=2. */
 34         cfg.base.is_pages = mentry.segments[2].flags.length;
 35         cfg.gtw_cfg.node_id = node_id;
 36         cfg.gtw_cfg.dma_buffer_size = buffer_size;
 37 
 38         return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg,
 39                                    sizeof(cfg), &dummy);
 40 }
 41 
 42 static void avs_dsp_delete_probe(struct avs_dev *adev)
 43 {
 44         struct avs_module_entry mentry;
 45         int ret;
 46 
 47         ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
 48         if (!ret)
 49                 /* There is only ever one probe module instance. */
 50                 avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
 51 }
 52 
 53 static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream)
 54 {
 55         return cstream->runtime->private_data;
 56 }
 57 
 58 static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
 59 {
 60         struct avs_dev *adev = to_avs_dev(dai->dev);
 61         struct hdac_bus *bus = &adev->base.core;
 62         struct hdac_ext_stream *host_stream;
 63 
 64         if (adev->extractor) {
 65                 dev_err(dai->dev, "Cannot open more than one extractor stream\n");
 66                 return -EEXIST;
 67         }
 68 
 69         host_stream = snd_hdac_ext_cstream_assign(bus, cstream);
 70         if (!host_stream) {
 71                 dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n");
 72                 return -EBUSY;
 73         }
 74 
 75         adev->extractor = host_stream;
 76         hdac_stream(host_stream)->curr_pos = 0;
 77         cstream->runtime->private_data = host_stream;
 78 
 79         return 0;
 80 }
 81 
 82 static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
 83 {
 84         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
 85         struct avs_dev *adev = to_avs_dev(dai->dev);
 86         struct avs_probe_point_desc *desc;
 87         /* Extractor node identifier. */
 88         unsigned int vindex = INVALID_NODE_ID.vindex;
 89         size_t num_desc;
 90         int i, ret;
 91 
 92         /* Disconnect all probe points. */
 93         ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
 94         if (ret) {
 95                 dev_err(dai->dev, "get probe points failed: %d\n", ret);
 96                 ret = AVS_IPC_RET(ret);
 97                 goto exit;
 98         }
 99 
100         for (i = 0; i < num_desc; i++)
101                 if (desc[i].node_id.vindex == vindex)
102                         avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1);
103         kfree(desc);
104 
105 exit:
106         if (adev->num_probe_streams) {
107                 adev->num_probe_streams--;
108                 if (!adev->num_probe_streams) {
109                         avs_dsp_delete_probe(adev);
110                         avs_dsp_enable_d0ix(adev);
111                 }
112         }
113 
114         snd_hdac_stream_cleanup(hdac_stream(host_stream));
115         hdac_stream(host_stream)->prepared = 0;
116         snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST);
117 
118         snd_compr_free_pages(cstream);
119         adev->extractor = NULL;
120 
121         return ret;
122 }
123 
124 static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
125                                       struct snd_compr_params *params, struct snd_soc_dai *dai)
126 {
127         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
128         struct snd_compr_runtime *rtd = cstream->runtime;
129         struct avs_dev *adev = to_avs_dev(dai->dev);
130         /* compr params do not store bit depth, default to S32_LE. */
131         snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
132         unsigned int format_val;
133         int bps, ret;
134 
135         hdac_stream(host_stream)->bufsize = 0;
136         hdac_stream(host_stream)->period_bytes = 0;
137         hdac_stream(host_stream)->format_val = 0;
138         cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
139         cstream->dma_buffer.dev.dev = adev->dev;
140 
141         ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
142         if (ret < 0)
143                 return ret;
144         bps = snd_pcm_format_physical_width(format);
145         if (bps < 0)
146                 return bps;
147         format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
148         ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
149         if (ret < 0)
150                 return ret;
151         ret = snd_hdac_stream_setup(hdac_stream(host_stream), false);
152         if (ret < 0)
153                 return ret;
154 
155         hdac_stream(host_stream)->prepared = 1;
156 
157         if (!adev->num_probe_streams) {
158                 union avs_connector_node_id node_id;
159 
160                 /* D0ix not allowed during probing. */
161                 ret = avs_dsp_disable_d0ix(adev);
162                 if (ret)
163                         return ret;
164 
165                 node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
166                 node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
167 
168                 ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
169                 if (ret < 0) {
170                         dev_err(dai->dev, "probe init failed: %d\n", ret);
171                         avs_dsp_enable_d0ix(adev);
172                         return ret;
173                 }
174         }
175 
176         adev->num_probe_streams++;
177         return 0;
178 }
179 
180 static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
181                                    struct snd_soc_dai *dai)
182 {
183         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
184         struct avs_dev *adev = to_avs_dev(dai->dev);
185         struct hdac_bus *bus = &adev->base.core;
186         unsigned long cookie;
187 
188         if (!hdac_stream(host_stream)->prepared)
189                 return -EPIPE;
190 
191         switch (cmd) {
192         case SNDRV_PCM_TRIGGER_START:
193         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
194         case SNDRV_PCM_TRIGGER_RESUME:
195                 spin_lock_irqsave(&bus->reg_lock, cookie);
196                 snd_hdac_stream_start(hdac_stream(host_stream));
197                 spin_unlock_irqrestore(&bus->reg_lock, cookie);
198                 break;
199 
200         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
201         case SNDRV_PCM_TRIGGER_SUSPEND:
202         case SNDRV_PCM_TRIGGER_STOP:
203                 spin_lock_irqsave(&bus->reg_lock, cookie);
204                 snd_hdac_stream_stop(hdac_stream(host_stream));
205                 spin_unlock_irqrestore(&bus->reg_lock, cookie);
206                 break;
207 
208         default:
209                 return -EINVAL;
210         }
211 
212         return 0;
213 }
214 
215 static int avs_probe_compr_pointer(struct snd_compr_stream *cstream,
216                                    struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
217 {
218         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
219         struct snd_soc_pcm_stream *pstream;
220 
221         pstream = &dai->driver->capture;
222         tstamp->copied_total = hdac_stream(host_stream)->curr_pos;
223         tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
224 
225         return 0;
226 }
227 
228 static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream,
229                                 char __user *buf, size_t count)
230 {
231         struct snd_compr_runtime *rtd = cstream->runtime;
232         unsigned int offset, n;
233         void *ptr;
234         int ret;
235 
236         if (count > rtd->buffer_size)
237                 count = rtd->buffer_size;
238 
239         div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
240         ptr = rtd->dma_area + offset;
241         n = rtd->buffer_size - offset;
242 
243         if (count < n) {
244                 ret = copy_to_user(buf, ptr, count);
245         } else {
246                 ret = copy_to_user(buf, ptr, n);
247                 ret += copy_to_user(buf + n, rtd->dma_area, count - n);
248         }
249 
250         if (ret)
251                 return count - ret;
252         return count;
253 }
254 
255 static const struct snd_soc_cdai_ops avs_probe_cdai_ops = {
256         .startup = avs_probe_compr_open,
257         .shutdown = avs_probe_compr_free,
258         .set_params = avs_probe_compr_set_params,
259         .trigger = avs_probe_compr_trigger,
260         .pointer = avs_probe_compr_pointer,
261 };
262 
263 static const struct snd_soc_dai_ops avs_probe_dai_ops = {
264         .compress_new = snd_soc_new_compress,
265 };
266 
267 static const struct snd_compress_ops avs_probe_compress_ops = {
268         .copy = avs_probe_compr_copy,
269 };
270 
271 static struct snd_soc_dai_driver probe_cpu_dais[] = {
272 {
273         .name = "Probe Extraction CPU DAI",
274         .cops = &avs_probe_cdai_ops,
275         .ops  = &avs_probe_dai_ops,
276         .capture = {
277                 .stream_name = "Probe Extraction",
278                 .channels_min = 1,
279                 .channels_max = 8,
280                 .rates = SNDRV_PCM_RATE_48000,
281                 .rate_min = 48000,
282                 .rate_max = 48000,
283         },
284 },
285 };
286 
287 static const struct snd_soc_component_driver avs_probe_component_driver = {
288         .name                   = "avs-probe-compr",
289         .compress_ops           = &avs_probe_compress_ops,
290         .module_get_upon_open   = 1, /* increment refcount when a stream is opened */
291 };
292 
293 int avs_probe_platform_register(struct avs_dev *adev, const char *name)
294 {
295         return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver,
296                                           probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
297 }
298 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php