blob: 530fee936ed7ee8e0a47128980cadc57c1302cba [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 Girdwood3488cce2017-08-10 11:59:08 +010046/*
47 * Components, buffers and pipelines all use the same set of monotonic ID
48 * numbers passed in by the host. They are stored in different lists, hence
49 * more than 1 list may need to be searched for the correspodning component.
50 */
51
Liam Girdwood425aa5e2017-06-06 20:34:10 +010052struct ipc_comp_dev *ipc_get_comp(struct ipc *ipc, uint32_t id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010053{
54 struct ipc_comp_dev *icd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +010055 struct list_item *clist;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010056
Liam Girdwood425aa5e2017-06-06 20:34:10 +010057 list_for_item(clist, &ipc->comp_list) {
58 icd = container_of(clist, struct ipc_comp_dev, list);
Liam Girdwood3488cce2017-08-10 11:59:08 +010059 switch (icd->type) {
60 case COMP_TYPE_COMPONENT:
61 if (icd->cd->comp.id == id)
62 return icd;
63 break;
64 case COMP_TYPE_BUFFER:
65 if (icd->cb->ipc_buffer.comp.id == id)
66 return icd;
67 break;
68 case COMP_TYPE_PIPELINE:
69 if (icd->pipeline->ipc_pipe.comp_id == id)
70 return icd;
71 break;
72 default:
73 break;
74 }
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010075 }
76
Liam Girdwood425aa5e2017-06-06 20:34:10 +010077 return NULL;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010078}
79
Liam Girdwood425aa5e2017-06-06 20:34:10 +010080int ipc_comp_new(struct ipc *ipc, struct sof_ipc_comp *comp)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010081{
Liam Girdwood425aa5e2017-06-06 20:34:10 +010082 struct comp_dev *cd;
83 struct ipc_comp_dev *icd;
84 int ret = 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010085
Liam Girdwood425aa5e2017-06-06 20:34:10 +010086 /* check whether component already exists */
87 icd = ipc_get_comp(ipc, comp->id);
88 if (icd != NULL) {
89 trace_ipc_error("eCe");
90 trace_value(comp->id);
91 return -EINVAL;
92 }
93
94 /* create component */
95 cd = comp_new(comp);
96 if (cd == NULL) {
97 trace_ipc_error("eCn");
98 return -EINVAL;
99 }
100
101 /* allocate the IPC component container */
102 icd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(struct ipc_comp_dev));
103 if (icd == NULL) {
104 trace_ipc_error("eCm");
105 rfree(cd);
106 return -ENOMEM;
107 }
108 icd->cd = cd;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100109 icd->type = COMP_TYPE_COMPONENT;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100110
111 /* add new component to the list */
112 list_item_append(&icd->list, &ipc->comp_list);
113 return ret;
114}
115
Liam Girdwood3488cce2017-08-10 11:59:08 +0100116int ipc_comp_free(struct ipc *ipc, uint32_t comp_id)
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100117{
118 struct ipc_comp_dev *icd;
119
120 /* check whether component exists */
121 icd = ipc_get_comp(ipc, comp_id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100122 if (icd == NULL)
Liam Girdwood3488cce2017-08-10 11:59:08 +0100123 return -ENODEV;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100124
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100125 /* free component and remove from list */
126 comp_free(icd->cd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100127 list_item_del(&icd->list);
Liam Girdwood50f7b0e2017-06-06 12:52:15 +0100128 rfree(icd);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100129
130 return 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100131}
132
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100133int ipc_buffer_new(struct ipc *ipc, struct sof_ipc_buffer *desc)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100134{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100135 struct ipc_comp_dev *ibd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100136 struct comp_buffer *buffer;
137 int ret = 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100138
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100139 /* check whether buffer already exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100140 ibd = ipc_get_comp(ipc, desc->comp.id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100141 if (ibd != NULL) {
142 trace_ipc_error("eBe");
Liam Girdwood3488cce2017-08-10 11:59:08 +0100143 trace_value(desc->comp.id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100144 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100145 }
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100146
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100147 /* register buffer with pipeline */
148 buffer = buffer_new(desc);
149 if (buffer == NULL) {
150 trace_ipc_error("eBn");
151 rfree(ibd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100152 return -ENOMEM;
153 }
154
Liam Girdwood3488cce2017-08-10 11:59:08 +0100155 ibd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(struct ipc_comp_dev));
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100156 if (ibd == NULL) {
157 rfree(buffer);
158 return -ENOMEM;
159 }
160 ibd->cb = buffer;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100161 ibd->type = COMP_TYPE_BUFFER;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100162
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100163 /* add new buffer to the list */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100164 list_item_append(&ibd->list, &ipc->comp_list);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100165 return ret;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100166}
167
Liam Girdwood3488cce2017-08-10 11:59:08 +0100168int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100169{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100170 struct ipc_comp_dev *ibd;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100171
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100172 /* check whether buffer exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100173 ibd = ipc_get_comp(ipc, buffer_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100174 if (ibd == NULL)
Liam Girdwood3488cce2017-08-10 11:59:08 +0100175 return -ENODEV;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100176
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100177 /* free buffer and remove from list */
178 buffer_free(ibd->cb);
179 list_item_del(&ibd->list);
180 rfree(ibd);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100181
182 return 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100183}
184
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100185int ipc_comp_connect(struct ipc *ipc,
186 struct sof_ipc_pipe_comp_connect *connect)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100187{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100188 struct ipc_comp_dev *icd_source, *icd_sink;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100189 //struct ipc_comp_dev *icd_source_pipe, *icd_sink_pipe;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100190
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100191 /* check whether the components already exist */
192 icd_source = ipc_get_comp(ipc, connect->source_id);
193 if (icd_source == NULL) {
194 trace_ipc_error("eCr");
195 trace_value(connect->source_id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100196 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100197 }
198
199 icd_sink = ipc_get_comp(ipc, connect->sink_id);
200 if (icd_sink == NULL) {
201 trace_ipc_error("eCn");
202 trace_value(connect->sink_id);
203 return -EINVAL;
204 }
205
Liam Girdwood3488cce2017-08-10 11:59:08 +0100206 /* check source and sink types */
207 if (icd_source->type == COMP_TYPE_BUFFER &&
208 icd_sink->type == COMP_TYPE_COMPONENT)
209 return pipeline_buffer_connect(icd_source->pipeline,
210 icd_source->cb, icd_sink->cd);
211 else if (icd_source->type == COMP_TYPE_COMPONENT &&
212 icd_sink->type == COMP_TYPE_BUFFER)
213 return pipeline_comp_connect(icd_source->pipeline,
214 icd_source->cd, icd_sink->cb);
215 else {
216 trace_ipc_error("eCt");
217 trace_value(connect->source_id);
218 trace_value(connect->sink_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100219 return -EINVAL;
220 }
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100221}
222
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100223
224int ipc_pipeline_new(struct ipc *ipc,
225 struct sof_ipc_pipe_new *pipe_desc)
226{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100227 struct ipc_comp_dev *ipc_pipe;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100228 struct pipeline *pipe;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100229 struct ipc_comp_dev *icd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100230
231 /* check whether the pipeline already exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100232 ipc_pipe = ipc_get_comp(ipc, pipe_desc->comp_id);
233 if (ipc_pipe != NULL) {
234 trace_ipc_error("ePi");
235 trace_value(pipe_desc->comp_id);
236 return -EINVAL;
237 }
238
239 /* find the scheduling component */
240 icd = ipc_get_comp(ipc, pipe_desc->sched_id);
241 if (icd == NULL) {
242 trace_ipc_error("ePs");
243 trace_value(pipe_desc->sched_id);
244 return -EINVAL;
245 }
246 if (icd->type != COMP_TYPE_COMPONENT) {
247 trace_ipc_error("ePc");
248 return -EINVAL;
249 }
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100250
251 /* create the pipeline */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100252 pipe = pipeline_new(pipe_desc, icd->cd);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100253 if (pipe == NULL) {
254 trace_ipc_error("ePn");
255 return -ENOMEM;
256 }
257
258 /* allocate the IPC pipeline container */
259 ipc_pipe = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
Liam Girdwood3488cce2017-08-10 11:59:08 +0100260 sizeof(struct ipc_comp_dev));
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100261 if (ipc_pipe == NULL) {
Liam Girdwood3488cce2017-08-10 11:59:08 +0100262 pipeline_free(pipe);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100263 return -ENOMEM;
264 }
265
266 ipc_pipe->pipeline = pipe;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100267 ipc_pipe->type = COMP_TYPE_PIPELINE;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100268
269 /* add new pipeline to the list */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100270 list_item_append(&ipc_pipe->list, &ipc->comp_list);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100271 return 0;
272}
273
Liam Girdwood3488cce2017-08-10 11:59:08 +0100274int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id)
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100275{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100276 struct ipc_comp_dev *ipc_pipe;
277 int ret;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100278
279 /* check whether pipeline exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100280 ipc_pipe = ipc_get_comp(ipc, comp_id);
281 if (ipc_pipe == NULL)
282 return -ENODEV;
283
284 /* free buffer and remove from list */
285 ret = pipeline_free(ipc_pipe->pipeline);
286 if (ret < 0) {
287 trace_ipc_error("ePf");
288 return ret;
289 }
290
291 list_item_del(&ipc_pipe->list);
292 rfree(ipc_pipe);
293
294 return 0;
295}
296
297void ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id)
298{
299 struct ipc_comp_dev *ipc_pipe;
300
301 /* check whether pipeline exists */
302 ipc_pipe = ipc_get_comp(ipc, comp_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100303 if (ipc_pipe == NULL)
304 return;
305
306 /* free buffer and remove from list */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100307 pipeline_complete(ipc_pipe->pipeline);
308}
309
310int ipc_comp_dai_config(struct ipc *ipc, struct dai_config *config)
311{
312 struct ipc_comp_dev *icd;
313 struct list_item *clist;
314 int ret = 0;
315
316 /* for each component */
317 list_for_item(clist, &ipc->comp_list) {
318 icd = container_of(clist, struct ipc_comp_dev, list);
319 switch (icd->type) {
320 case COMP_TYPE_COMPONENT:
321
322 /* make sure we only config DAI comps */
323 switch (icd->cd->comp.type) {
324 case SOF_COMP_DAI:
325 case SOF_COMP_SG_DAI:
326 ret = comp_dai_config(icd->cd, config);
327 if (ret < 0) {
328 trace_ipc_error("eCD");
329 return ret;
330 }
331 break;
332 default:
333 break;
334 }
335
336 break;
337 /* ignore non components */
338 default:
339 break;
340 }
341 }
342
343 return ret;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100344}
345
Liam Girdwood69222cf2017-06-06 16:41:07 +0100346int ipc_init(struct reef *reef)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100347{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100348 trace_ipc("IPI");
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100349
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100350 /* init ipc data */
351 reef->ipc = rzalloc(RZONE_SYS, RFLAGS_NONE, sizeof(*reef->ipc));
352 reef->ipc->comp_data = rzalloc(RZONE_SYS, RFLAGS_NONE, SOF_IPC_MSG_MAX_SIZE);
353
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100354 list_init(&reef->ipc->comp_list);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100355
356 return platform_ipc_init(reef->ipc);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100357}