diff options
author | Olivier Moysan <olivier.moysan@st.com> | 2018-02-19 10:00:36 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-02-26 06:11:20 -0500 |
commit | 78648092ef46255e6dc6685202164199c86cf930 (patch) | |
tree | f226b44417b9638854052f6fb75b74d99e6ea9c9 | |
parent | 7ed310bd51bec0b440a551fc4da1993c7f6cd231 (diff) |
ASoC: dmaengine_pcm: add processing support
Allow dmaengine client to optionally register a processing callback.
This callback is intended to apply processing
on samples in buffer copied from/to user space, before/after DMA transfer.
Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | include/sound/dmaengine_pcm.h | 3 | ||||
-rw-r--r-- | sound/soc/soc-generic-dmaengine-pcm.c | 62 |
2 files changed, 63 insertions, 2 deletions
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 8a5a8404966e..47ef486852ed 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h | |||
@@ -140,6 +140,9 @@ struct snd_dmaengine_pcm_config { | |||
140 | struct dma_chan *(*compat_request_channel)( | 140 | struct dma_chan *(*compat_request_channel)( |
141 | struct snd_soc_pcm_runtime *rtd, | 141 | struct snd_soc_pcm_runtime *rtd, |
142 | struct snd_pcm_substream *substream); | 142 | struct snd_pcm_substream *substream); |
143 | int (*process)(struct snd_pcm_substream *substream, | ||
144 | int channel, unsigned long hwoff, | ||
145 | void *buf, unsigned long bytes); | ||
143 | dma_filter_fn compat_filter_fn; | 146 | dma_filter_fn compat_filter_fn; |
144 | struct device *dma_dev; | 147 | struct device *dma_dev; |
145 | const char *chan_names[SNDRV_PCM_STREAM_LAST + 1]; | 148 | const char *chan_names[SNDRV_PCM_STREAM_LAST + 1]; |
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 785f25ede3e5..567fbdfd1ca9 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c | |||
@@ -341,6 +341,41 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( | |||
341 | return snd_dmaengine_pcm_pointer(substream); | 341 | return snd_dmaengine_pcm_pointer(substream); |
342 | } | 342 | } |
343 | 343 | ||
344 | static int dmaengine_copy_user(struct snd_pcm_substream *substream, | ||
345 | int channel, unsigned long hwoff, | ||
346 | void *buf, unsigned long bytes) | ||
347 | { | ||
348 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
349 | struct snd_soc_component *component = | ||
350 | snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); | ||
351 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
352 | struct dmaengine_pcm *pcm = soc_component_to_pcm(component); | ||
353 | int (*process)(struct snd_pcm_substream *substream, | ||
354 | int channel, unsigned long hwoff, | ||
355 | void *buf, unsigned long bytes) = pcm->config->process; | ||
356 | bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
357 | void *dma_ptr = runtime->dma_area + hwoff + | ||
358 | channel * (runtime->dma_bytes / runtime->channels); | ||
359 | int ret; | ||
360 | |||
361 | if (is_playback) | ||
362 | if (copy_from_user(dma_ptr, (void __user *)buf, bytes)) | ||
363 | return -EFAULT; | ||
364 | |||
365 | if (process) { | ||
366 | ret = process(substream, channel, hwoff, | ||
367 | (void __user *)buf, bytes); | ||
368 | if (ret < 0) | ||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | if (!is_playback) | ||
373 | if (copy_to_user((void __user *)buf, dma_ptr, bytes)) | ||
374 | return -EFAULT; | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
344 | static const struct snd_pcm_ops dmaengine_pcm_ops = { | 379 | static const struct snd_pcm_ops dmaengine_pcm_ops = { |
345 | .open = dmaengine_pcm_open, | 380 | .open = dmaengine_pcm_open, |
346 | .close = snd_dmaengine_pcm_close, | 381 | .close = snd_dmaengine_pcm_close, |
@@ -351,6 +386,17 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { | |||
351 | .pointer = dmaengine_pcm_pointer, | 386 | .pointer = dmaengine_pcm_pointer, |
352 | }; | 387 | }; |
353 | 388 | ||
389 | static const struct snd_pcm_ops dmaengine_pcm_process_ops = { | ||
390 | .open = dmaengine_pcm_open, | ||
391 | .close = snd_dmaengine_pcm_close, | ||
392 | .ioctl = snd_pcm_lib_ioctl, | ||
393 | .hw_params = dmaengine_pcm_hw_params, | ||
394 | .hw_free = snd_pcm_lib_free_pages, | ||
395 | .trigger = snd_dmaengine_pcm_trigger, | ||
396 | .pointer = dmaengine_pcm_pointer, | ||
397 | .copy_user = dmaengine_copy_user, | ||
398 | }; | ||
399 | |||
354 | static const struct snd_soc_component_driver dmaengine_pcm_component = { | 400 | static const struct snd_soc_component_driver dmaengine_pcm_component = { |
355 | .name = SND_DMAENGINE_PCM_DRV_NAME, | 401 | .name = SND_DMAENGINE_PCM_DRV_NAME, |
356 | .probe_order = SND_SOC_COMP_ORDER_LATE, | 402 | .probe_order = SND_SOC_COMP_ORDER_LATE, |
@@ -358,6 +404,13 @@ static const struct snd_soc_component_driver dmaengine_pcm_component = { | |||
358 | .pcm_new = dmaengine_pcm_new, | 404 | .pcm_new = dmaengine_pcm_new, |
359 | }; | 405 | }; |
360 | 406 | ||
407 | static const struct snd_soc_component_driver dmaengine_pcm_component_process = { | ||
408 | .name = SND_DMAENGINE_PCM_DRV_NAME, | ||
409 | .probe_order = SND_SOC_COMP_ORDER_LATE, | ||
410 | .ops = &dmaengine_pcm_process_ops, | ||
411 | .pcm_new = dmaengine_pcm_new, | ||
412 | }; | ||
413 | |||
361 | static const char * const dmaengine_pcm_dma_channel_names[] = { | 414 | static const char * const dmaengine_pcm_dma_channel_names[] = { |
362 | [SNDRV_PCM_STREAM_PLAYBACK] = "tx", | 415 | [SNDRV_PCM_STREAM_PLAYBACK] = "tx", |
363 | [SNDRV_PCM_STREAM_CAPTURE] = "rx", | 416 | [SNDRV_PCM_STREAM_CAPTURE] = "rx", |
@@ -453,8 +506,13 @@ int snd_dmaengine_pcm_register(struct device *dev, | |||
453 | if (ret) | 506 | if (ret) |
454 | goto err_free_pcm; | 507 | goto err_free_pcm; |
455 | 508 | ||
456 | ret = snd_soc_add_component(dev, &pcm->component, | 509 | if (config && config->process) |
457 | &dmaengine_pcm_component, NULL, 0); | 510 | ret = snd_soc_add_component(dev, &pcm->component, |
511 | &dmaengine_pcm_component_process, | ||
512 | NULL, 0); | ||
513 | else | ||
514 | ret = snd_soc_add_component(dev, &pcm->component, | ||
515 | &dmaengine_pcm_component, NULL, 0); | ||
458 | if (ret) | 516 | if (ret) |
459 | goto err_free_dma; | 517 | goto err_free_dma; |
460 | 518 | ||