stream-ipc.c (2675B)
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 23struct sof_stream { 24 size_t posn_offset; 25}; 26 27/* Mailbox-based Generic IPC implementation */ 28int 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} 46EXPORT_SYMBOL(sof_ipc_msg_data); 47 48int 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} 66EXPORT_SYMBOL(sof_set_stream_data_offset); 67 68int 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} 88EXPORT_SYMBOL(sof_stream_pcm_open); 89 90int 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} 100EXPORT_SYMBOL(sof_stream_pcm_close); 101 102MODULE_LICENSE("Dual BSD/GPL");