probes.c (dab8d000e25c3e91154efca287434a4f78ab65d2) | probes.c (700462f55493c6831ad71b209eaebe310dcf11fd) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4// 5// Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7// 8 | 1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 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> |
|
9#include "avs.h" 10#include "messages.h" 11 | 13#include "avs.h" 14#include "messages.h" 15 |
12__maybe_unused | |
13static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id, 14 size_t buffer_size) | 16static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id, 17 size_t buffer_size) |
15 | |
16{ 17 struct avs_probe_cfg cfg = {{0}}; 18 struct avs_module_entry mentry; 19 u16 dummy; 20 21 avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); 22 23 /* --- 5 unchanged lines hidden (view full) --- 29 cfg.base.is_pages = mentry.segments[2].flags.length; 30 cfg.gtw_cfg.node_id = node_id; 31 cfg.gtw_cfg.dma_buffer_size = buffer_size; 32 33 return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg, 34 sizeof(cfg), &dummy); 35} 36 | 18{ 19 struct avs_probe_cfg cfg = {{0}}; 20 struct avs_module_entry mentry; 21 u16 dummy; 22 23 avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); 24 25 /* --- 5 unchanged lines hidden (view full) --- 31 cfg.base.is_pages = mentry.segments[2].flags.length; 32 cfg.gtw_cfg.node_id = node_id; 33 cfg.gtw_cfg.dma_buffer_size = buffer_size; 34 35 return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg, 36 sizeof(cfg), &dummy); 37} 38 |
37__maybe_unused | |
38static void avs_dsp_delete_probe(struct avs_dev *adev) 39{ 40 struct avs_module_entry mentry; 41 42 avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); 43 44 /* There is only ever one probe module instance. */ 45 avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); 46} | 39static void avs_dsp_delete_probe(struct avs_dev *adev) 40{ 41 struct avs_module_entry mentry; 42 43 avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); 44 45 /* There is only ever one probe module instance. */ 46 avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); 47} |
48 49static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream) 50{ 51 return cstream->runtime->private_data; 52} 53 54static 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 78static 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 101exit: 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 120static 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 177static 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 212static 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 225static 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 253static 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 262static const struct snd_compress_ops avs_probe_compress_ops = { 263 .copy = avs_probe_compr_copy, 264}; |
|