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