stream-ipc.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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 Intel Corporation
  7. //
  8. // Authors: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
  9. /* Generic SOF IPC code */
  10. #include <linux/device.h>
  11. #include <linux/export.h>
  12. #include <linux/module.h>
  13. #include <linux/types.h>
  14. #include <sound/pcm.h>
  15. #include <sound/sof/stream.h>
  16. #include "ops.h"
  17. #include "sof-priv.h"
  18. #include "sof-audio.h"
  19. struct sof_stream {
  20. size_t posn_offset;
  21. };
  22. /* Mailbox-based Generic IPC implementation */
  23. int sof_ipc_msg_data(struct snd_sof_dev *sdev,
  24. struct snd_sof_pcm_stream *sps,
  25. void *p, size_t sz)
  26. {
  27. if (!sps || !sdev->stream_box.size) {
  28. snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
  29. } else {
  30. size_t posn_offset;
  31. if (sps->substream) {
  32. struct sof_stream *stream = sps->substream->runtime->private_data;
  33. /* The stream might already be closed */
  34. if (!stream)
  35. return -ESTRPIPE;
  36. posn_offset = stream->posn_offset;
  37. } else if (sps->cstream) {
  38. struct sof_compr_stream *sstream = sps->cstream->runtime->private_data;
  39. if (!sstream)
  40. return -ESTRPIPE;
  41. posn_offset = sstream->posn_offset;
  42. } else {
  43. dev_err(sdev->dev, "%s: No stream opened\n", __func__);
  44. return -EINVAL;
  45. }
  46. snd_sof_dsp_mailbox_read(sdev, posn_offset, p, sz);
  47. }
  48. return 0;
  49. }
  50. EXPORT_SYMBOL(sof_ipc_msg_data);
  51. int sof_set_stream_data_offset(struct snd_sof_dev *sdev,
  52. struct snd_sof_pcm_stream *sps,
  53. size_t posn_offset)
  54. {
  55. /* check if offset is overflow or it is not aligned */
  56. if (posn_offset > sdev->stream_box.size ||
  57. posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
  58. return -EINVAL;
  59. posn_offset += sdev->stream_box.offset;
  60. if (sps->substream) {
  61. struct sof_stream *stream = sps->substream->runtime->private_data;
  62. stream->posn_offset = posn_offset;
  63. dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
  64. sps->substream->stream, posn_offset);
  65. } else if (sps->cstream) {
  66. struct sof_compr_stream *sstream = sps->cstream->runtime->private_data;
  67. sstream->posn_offset = posn_offset;
  68. dev_dbg(sdev->dev, "compr: stream dir %d, posn mailbox offset is %zu",
  69. sps->cstream->direction, posn_offset);
  70. } else {
  71. dev_err(sdev->dev, "No stream opened");
  72. return -EINVAL;
  73. }
  74. return 0;
  75. }
  76. EXPORT_SYMBOL(sof_set_stream_data_offset);
  77. int sof_stream_pcm_open(struct snd_sof_dev *sdev,
  78. struct snd_pcm_substream *substream)
  79. {
  80. struct sof_stream *stream = kmalloc_obj(*stream);
  81. if (!stream)
  82. return -ENOMEM;
  83. /* binding pcm substream to hda stream */
  84. substream->runtime->private_data = stream;
  85. /* align to DMA minimum transfer size */
  86. snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
  87. /* avoid circular buffer wrap in middle of period */
  88. snd_pcm_hw_constraint_integer(substream->runtime,
  89. SNDRV_PCM_HW_PARAM_PERIODS);
  90. return 0;
  91. }
  92. EXPORT_SYMBOL(sof_stream_pcm_open);
  93. int sof_stream_pcm_close(struct snd_sof_dev *sdev,
  94. struct snd_pcm_substream *substream)
  95. {
  96. struct sof_stream *stream = substream->runtime->private_data;
  97. substream->runtime->private_data = NULL;
  98. kfree(stream);
  99. return 0;
  100. }
  101. EXPORT_SYMBOL(sof_stream_pcm_close);