stream-ipc.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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. All rights reserved.
  7. //
  8. // Authors: Guennadi Liakhovetski <[email protected]>
  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. struct sof_stream {
  19. size_t posn_offset;
  20. };
  21. /* Mailbox-based Generic IPC implementation */
  22. int sof_ipc_msg_data(struct snd_sof_dev *sdev,
  23. struct snd_pcm_substream *substream,
  24. void *p, size_t sz)
  25. {
  26. if (!substream || !sdev->stream_box.size) {
  27. snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
  28. } else {
  29. struct sof_stream *stream = substream->runtime->private_data;
  30. /* The stream might already be closed */
  31. if (!stream)
  32. return -ESTRPIPE;
  33. snd_sof_dsp_mailbox_read(sdev, stream->posn_offset, p, sz);
  34. }
  35. return 0;
  36. }
  37. EXPORT_SYMBOL(sof_ipc_msg_data);
  38. int sof_set_stream_data_offset(struct snd_sof_dev *sdev,
  39. struct snd_pcm_substream *substream,
  40. size_t posn_offset)
  41. {
  42. struct sof_stream *stream = substream->runtime->private_data;
  43. /* check if offset is overflow or it is not aligned */
  44. if (posn_offset > sdev->stream_box.size ||
  45. posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
  46. return -EINVAL;
  47. stream->posn_offset = sdev->stream_box.offset + posn_offset;
  48. dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
  49. substream->stream, stream->posn_offset);
  50. return 0;
  51. }
  52. EXPORT_SYMBOL(sof_set_stream_data_offset);
  53. int sof_stream_pcm_open(struct snd_sof_dev *sdev,
  54. struct snd_pcm_substream *substream)
  55. {
  56. struct sof_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
  57. if (!stream)
  58. return -ENOMEM;
  59. /* binding pcm substream to hda stream */
  60. substream->runtime->private_data = stream;
  61. /* align to DMA minimum transfer size */
  62. snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
  63. /* avoid circular buffer wrap in middle of period */
  64. snd_pcm_hw_constraint_integer(substream->runtime,
  65. SNDRV_PCM_HW_PARAM_PERIODS);
  66. return 0;
  67. }
  68. EXPORT_SYMBOL(sof_stream_pcm_open);
  69. int sof_stream_pcm_close(struct snd_sof_dev *sdev,
  70. struct snd_pcm_substream *substream)
  71. {
  72. struct sof_stream *stream = substream->runtime->private_data;
  73. substream->runtime->private_data = NULL;
  74. kfree(stream);
  75. return 0;
  76. }
  77. EXPORT_SYMBOL(sof_stream_pcm_close);
  78. MODULE_LICENSE("Dual BSD/GPL");