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 | #include "sof-audio.h" |
23 | |
24 | struct sof_stream { |
25 | size_t posn_offset; |
26 | }; |
27 | |
28 | /* Mailbox-based Generic IPC implementation */ |
29 | int sof_ipc_msg_data(struct snd_sof_dev *sdev, |
30 | struct snd_sof_pcm_stream *sps, |
31 | void *p, size_t sz) |
32 | { |
33 | if (!sps || !sdev->stream_box.size) { |
34 | snd_sof_dsp_mailbox_read(sdev, offset: sdev->dsp_box.offset, dest: p, bytes: sz); |
35 | } else { |
36 | size_t posn_offset; |
37 | |
38 | if (sps->substream) { |
39 | struct sof_stream *stream = sps->substream->runtime->private_data; |
40 | |
41 | /* The stream might already be closed */ |
42 | if (!stream) |
43 | return -ESTRPIPE; |
44 | |
45 | posn_offset = stream->posn_offset; |
46 | } else { |
47 | |
48 | struct sof_compr_stream *sstream = sps->cstream->runtime->private_data; |
49 | |
50 | if (!sstream) |
51 | return -ESTRPIPE; |
52 | |
53 | posn_offset = sstream->posn_offset; |
54 | } |
55 | |
56 | snd_sof_dsp_mailbox_read(sdev, offset: posn_offset, dest: p, bytes: sz); |
57 | } |
58 | |
59 | return 0; |
60 | } |
61 | EXPORT_SYMBOL(sof_ipc_msg_data); |
62 | |
63 | int sof_set_stream_data_offset(struct snd_sof_dev *sdev, |
64 | struct snd_sof_pcm_stream *sps, |
65 | size_t posn_offset) |
66 | { |
67 | /* check if offset is overflow or it is not aligned */ |
68 | if (posn_offset > sdev->stream_box.size || |
69 | posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) |
70 | return -EINVAL; |
71 | |
72 | posn_offset += sdev->stream_box.offset; |
73 | |
74 | if (sps->substream) { |
75 | struct sof_stream *stream = sps->substream->runtime->private_data; |
76 | |
77 | stream->posn_offset = posn_offset; |
78 | dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu" , |
79 | sps->substream->stream, posn_offset); |
80 | } else if (sps->cstream) { |
81 | struct sof_compr_stream *sstream = sps->cstream->runtime->private_data; |
82 | |
83 | sstream->posn_offset = posn_offset; |
84 | dev_dbg(sdev->dev, "compr: stream dir %d, posn mailbox offset is %zu" , |
85 | sps->cstream->direction, posn_offset); |
86 | } else { |
87 | dev_err(sdev->dev, "No stream opened" ); |
88 | return -EINVAL; |
89 | } |
90 | |
91 | return 0; |
92 | } |
93 | EXPORT_SYMBOL(sof_set_stream_data_offset); |
94 | |
95 | int sof_stream_pcm_open(struct snd_sof_dev *sdev, |
96 | struct snd_pcm_substream *substream) |
97 | { |
98 | struct sof_stream *stream = kmalloc(size: sizeof(*stream), GFP_KERNEL); |
99 | |
100 | if (!stream) |
101 | return -ENOMEM; |
102 | |
103 | /* binding pcm substream to hda stream */ |
104 | substream->runtime->private_data = stream; |
105 | |
106 | /* align to DMA minimum transfer size */ |
107 | snd_pcm_hw_constraint_step(runtime: substream->runtime, cond: 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, step: 4); |
108 | |
109 | /* avoid circular buffer wrap in middle of period */ |
110 | snd_pcm_hw_constraint_integer(runtime: substream->runtime, |
111 | SNDRV_PCM_HW_PARAM_PERIODS); |
112 | |
113 | return 0; |
114 | } |
115 | EXPORT_SYMBOL(sof_stream_pcm_open); |
116 | |
117 | int sof_stream_pcm_close(struct snd_sof_dev *sdev, |
118 | struct snd_pcm_substream *substream) |
119 | { |
120 | struct sof_stream *stream = substream->runtime->private_data; |
121 | |
122 | substream->runtime->private_data = NULL; |
123 | kfree(objp: stream); |
124 | |
125 | return 0; |
126 | } |
127 | EXPORT_SYMBOL(sof_stream_pcm_close); |
128 | |
129 | MODULE_LICENSE("Dual BSD/GPL" ); |
130 | |