blob: 7c9193f05625552d620a0a48c7dd9d8e7c0757fc [file] [log] [blame]
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +01001/*
2 * Copyright (c) 2016, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Intel Corporation nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
29 * Keyon Jie <yang.jie@linux.intel.com>
30 */
31
32#include <stdint.h>
33#include <stddef.h>
34#include <errno.h>
35#include <reef/reef.h>
36#include <reef/lock.h>
37#include <reef/list.h>
38#include <reef/stream.h>
39#include <reef/alloc.h>
40#include <reef/ipc.h>
41#include <reef/debug.h>
42#include <reef/audio/component.h>
43#include <reef/audio/pipeline.h>
Liam Girdwood425aa5e2017-06-06 20:34:10 +010044#include <reef/audio/buffer.h>
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010045
Liam Girdwood425aa5e2017-06-06 20:34:10 +010046struct ipc_comp_dev *ipc_get_comp(struct ipc *ipc, uint32_t id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010047{
48 struct ipc_comp_dev *icd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +010049 struct list_item *clist;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010050
Liam Girdwood425aa5e2017-06-06 20:34:10 +010051 list_for_item(clist, &ipc->comp_list) {
52 icd = container_of(clist, struct ipc_comp_dev, list);
53 if (icd->cd->comp.id == id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010054 return icd;
55 }
56
57 return NULL;
58}
59
Liam Girdwood425aa5e2017-06-06 20:34:10 +010060struct ipc_buffer_dev *ipc_get_buffer(struct ipc *ipc, uint32_t id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010061{
Liam Girdwood425aa5e2017-06-06 20:34:10 +010062 struct ipc_buffer_dev *icb;
63 struct list_item *clist;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010064
Liam Girdwood425aa5e2017-06-06 20:34:10 +010065 list_for_item(clist, &ipc->buffer_list) {
66 icb = container_of(clist, struct ipc_buffer_dev, list);
67 if (icb->cb->ipc_buffer.comp.id == id)
68 return icb;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010069 }
70
71 return NULL;
72}
73
Liam Girdwood425aa5e2017-06-06 20:34:10 +010074struct ipc_pipeline_dev *ipc_get_pipeline(struct ipc *ipc, uint32_t id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010075{
Liam Girdwood425aa5e2017-06-06 20:34:10 +010076 struct ipc_pipeline_dev *ipd;
77 struct list_item *clist;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010078
Liam Girdwood425aa5e2017-06-06 20:34:10 +010079 list_for_item(clist, &ipc->pipeline_list) {
80 ipd = container_of(clist, struct ipc_pipeline_dev, list);
81 if (ipd->pipeline->id == id)
82 return ipd;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010083 }
84
Liam Girdwood425aa5e2017-06-06 20:34:10 +010085 return NULL;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010086}
87
Liam Girdwood425aa5e2017-06-06 20:34:10 +010088int ipc_comp_new(struct ipc *ipc, struct sof_ipc_comp *comp)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010089{
Liam Girdwood425aa5e2017-06-06 20:34:10 +010090 struct comp_dev *cd;
91 struct ipc_comp_dev *icd;
92 int ret = 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010093
Liam Girdwood425aa5e2017-06-06 20:34:10 +010094 /* check whether component already exists */
95 icd = ipc_get_comp(ipc, comp->id);
96 if (icd != NULL) {
97 trace_ipc_error("eCe");
98 trace_value(comp->id);
99 return -EINVAL;
100 }
101
102 /* create component */
103 cd = comp_new(comp);
104 if (cd == NULL) {
105 trace_ipc_error("eCn");
106 return -EINVAL;
107 }
108
109 /* allocate the IPC component container */
110 icd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(struct ipc_comp_dev));
111 if (icd == NULL) {
112 trace_ipc_error("eCm");
113 rfree(cd);
114 return -ENOMEM;
115 }
116 icd->cd = cd;
117
118 /* add new component to the list */
119 list_item_append(&icd->list, &ipc->comp_list);
120 return ret;
121}
122
123void ipc_comp_free(struct ipc *ipc, uint32_t comp_id)
124{
125 struct ipc_comp_dev *icd;
126
127 /* check whether component exists */
128 icd = ipc_get_comp(ipc, comp_id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100129 if (icd == NULL)
130 return;
131
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100132 /* free component and remove from list */
133 comp_free(icd->cd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100134 list_item_del(&icd->list);
Liam Girdwood50f7b0e2017-06-06 12:52:15 +0100135 rfree(icd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100136}
137
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100138int ipc_buffer_new(struct ipc *ipc, struct sof_ipc_buffer *desc)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100139{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100140 struct ipc_buffer_dev *ibd;
141 struct comp_buffer *buffer;
142 int ret = 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100143
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100144 /* check whether buffer already exists */
145 ibd = ipc_get_buffer(ipc, desc->comp.id);
146 if (ibd != NULL) {
147 trace_ipc_error("eBe");
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100148 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100149 }
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100150
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100151 /* register buffer with pipeline */
152 buffer = buffer_new(desc);
153 if (buffer == NULL) {
154 trace_ipc_error("eBn");
155 rfree(ibd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100156 return -ENOMEM;
157 }
158
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100159 ibd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(struct ipc_buffer_dev));
160 if (ibd == NULL) {
161 rfree(buffer);
162 return -ENOMEM;
163 }
164 ibd->cb = buffer;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100165
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100166 /* add new buffer to the list */
167 list_item_append(&ibd->list, &ipc->buffer_list);
168 return ret;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100169}
170
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100171void ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100172{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100173 struct ipc_buffer_dev *ibd;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100174
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100175 /* check whether buffer exists */
176 ibd = ipc_get_buffer(ipc, buffer_id);
177 if (ibd == NULL)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100178 return;
179
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100180 /* free buffer and remove from list */
181 buffer_free(ibd->cb);
182 list_item_del(&ibd->list);
183 rfree(ibd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100184}
185
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100186int ipc_comp_connect(struct ipc *ipc,
187 struct sof_ipc_pipe_comp_connect *connect)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100188{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100189 struct ipc_comp_dev *icd_source, *icd_sink;
190 struct ipc_buffer_dev *ibd;
191 struct ipc_pipeline_dev *ipc_pipe;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100192
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100193 /* check whether the components already exist */
194 icd_source = ipc_get_comp(ipc, connect->source_id);
195 if (icd_source == NULL) {
196 trace_ipc_error("eCr");
197 trace_value(connect->source_id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100198 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100199 }
200
201 icd_sink = ipc_get_comp(ipc, connect->sink_id);
202 if (icd_sink == NULL) {
203 trace_ipc_error("eCn");
204 trace_value(connect->sink_id);
205 return -EINVAL;
206 }
207
208 /* check whether the buffer already exists */
209 ibd = ipc_get_buffer(ipc, connect->buffer_id);
210 if (ibd == NULL) {
211 trace_ipc_error("eCb");
212 trace_value(connect->buffer_id);
213 return -EINVAL;
214 }
215
216 /* check whether the pipeline already exists */
217 ipc_pipe = ipc_get_pipeline(ipc, connect->pipeline_id);
218 if (ipc_pipe == NULL) {
219 trace_ipc_error("eCp");
220 trace_value(connect->pipeline_id);
221 return -EINVAL;
222 }
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100223
224 /* must be on same pipeline */
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100225 //if (connect->pipeline_id != icd_source->)
226 //return -EINVAL;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100227
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100228 return pipeline_comp_connect(ipc_pipe->pipeline,
229 icd_source->cd, icd_sink->cd, ibd->cb);
230}
231
232int ipc_pipe_connect(struct ipc *ipc,
233 struct sof_ipc_pipe_pipe_connect *connect)
234{
235 struct ipc_comp_dev *icd_source, *icd_sink;
236 struct ipc_buffer_dev *ibd;
237 struct ipc_pipeline_dev *ipc_pipe_source, *ipc_pipe_sink;
238
239 /* check whether the components already exist */
240 icd_source = ipc_get_comp(ipc, connect->comp_source_id);
Liam Girdwood9e8b23d2017-06-09 17:57:19 +0100241 if (icd_source == NULL) {
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100242 trace_ipc_error("eCr");
243 trace_value(connect->comp_source_id);
244 return EINVAL;
245 }
246
247 icd_sink = ipc_get_comp(ipc, connect->comp_sink_id);
248 if (icd_sink == NULL) {
249 trace_ipc_error("eCn");
250 trace_value(connect->comp_sink_id);
251 return EINVAL;
252 }
253
254 /* check whether the buffer already exists */
255 ibd = ipc_get_buffer(ipc, connect->buffer_id);
256 if (ibd == NULL) {
257 trace_ipc_error("eCb");
258 trace_value(connect->buffer_id);
259 return EINVAL;
260 }
261
262 /* check whether the pipelines already exist */
263 ipc_pipe_source = ipc_get_pipeline(ipc, connect->pipeline_source_id);
264 if (ipc_pipe_source == NULL) {
265 trace_ipc_error("eCp");
266 trace_value(connect->pipeline_source_id);
267 return EINVAL;
268 }
269
270 ipc_pipe_sink = ipc_get_pipeline(ipc, connect->pipeline_sink_id);
271 if (ipc_pipe_sink == NULL) {
272 trace_ipc_error("eCP");
273 trace_value(connect->pipeline_sink_id);
274 return EINVAL;
275 }
276
277 return pipeline_pipe_connect(ipc_pipe_source->pipeline,
278 ipc_pipe_sink->pipeline, icd_source->cd, icd_sink->cd, ibd->cb);
279}
280
281int ipc_pipeline_new(struct ipc *ipc,
282 struct sof_ipc_pipe_new *pipe_desc)
283{
284 struct ipc_pipeline_dev *ipc_pipe;
285 struct pipeline *pipe;
286
287 /* check whether the pipeline already exists */
288 ipc_pipe = ipc_get_pipeline(ipc, pipe_desc->pipeline_id);
289 if (ipc_pipe != NULL)
290 return EINVAL;
291
292 /* create the pipeline */
293 pipe = pipeline_new(pipe_desc);
294 if (pipe == NULL) {
295 trace_ipc_error("ePn");
296 return -ENOMEM;
297 }
298
299 /* allocate the IPC pipeline container */
300 ipc_pipe = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
301 sizeof(struct ipc_pipeline_dev));
302 if (ipc_pipe == NULL) {
303 rfree(pipe);
304 return -ENOMEM;
305 }
306
307 ipc_pipe->pipeline = pipe;
308
309 /* add new pipeline to the list */
310 list_item_append(&ipc_pipe->list, &ipc->pipeline_list);
311 return 0;
312}
313
314void ipc_pipeline_free(struct ipc *ipc, uint32_t pipeline_id)
315{
316 struct ipc_pipeline_dev *ipc_pipe;
317
318 /* check whether pipeline exists */
319 ipc_pipe = ipc_get_pipeline(ipc, pipeline_id);
320 if (ipc_pipe == NULL)
321 return;
322
323 /* free buffer and remove from list */
324 pipeline_free(ipc_pipe->pipeline);
325 list_item_del(&ipc_pipe->list);
326 rfree(ipc_pipe);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100327}
328
Liam Girdwood69222cf2017-06-06 16:41:07 +0100329int ipc_init(struct reef *reef)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100330{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100331 trace_ipc("IPI");
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100332
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100333 /* init ipc data */
334 reef->ipc = rzalloc(RZONE_SYS, RFLAGS_NONE, sizeof(*reef->ipc));
335 reef->ipc->comp_data = rzalloc(RZONE_SYS, RFLAGS_NONE, SOF_IPC_MSG_MAX_SIZE);
336
337 list_init(&reef->ipc->buffer_list);
338 list_init(&reef->ipc->comp_list);
339 list_init(&reef->ipc->pipeline_list);
340
341 return platform_ipc_init(reef->ipc);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100342}