1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2020 Intel Corporation. All rights reserved.
4 //
5 // Author: Marcin Rajwa <marcin.rajwa@linux.intel.com>
6
7 /*
8 * A codec adapter component.
9 */
10
11 /**
12 * \file
13 * \brief Processing compoent aimed to work with external codec libraries
14 * \author Marcin Rajwa <marcin.rajwa@linux.intel.com>
15 */
16
17 #include <sof/audio/buffer.h>
18 #include <sof/audio/component.h>
19 #include <sof/audio/ipc-config.h>
20 #include <sof/audio/codec_adapter/codec_adapter.h>
21 #include <sof/audio/pipeline.h>
22 #include <sof/common.h>
23 #include <sof/platform.h>
24 #include <sof/ut.h>
25
26 int load_setup_config(struct comp_dev *dev, void *cfg, uint32_t size);
27 int validate_setup_config(struct ca_config *cfg);
28
29 /**
30 * \brief Create a codec adapter component.
31 * \param[in] drv - component driver pointer.
32 * \param[in] config - component ipc descriptor pointer.
33 *
34 * \return: a pointer to newly created codec adapter component.
35 */
codec_adapter_new(const struct comp_driver * drv,struct comp_ipc_config * config,struct codec_interface * interface,void * spec)36 struct comp_dev *codec_adapter_new(const struct comp_driver *drv,
37 struct comp_ipc_config *config,
38 struct codec_interface *interface,
39 void *spec)
40 {
41 int ret;
42 struct comp_dev *dev;
43 struct comp_data *cd;
44 struct ipc_config_process *ipc_codec_adapter = spec;
45
46 comp_cl_dbg(drv, "codec_adapter_new() start");
47
48 if (!drv || !config) {
49 comp_cl_err(drv, "codec_adapter_new(), wrong input params! drv = %x config = %x",
50 (uint32_t)drv, (uint32_t)config);
51 return NULL;
52 }
53
54 dev = comp_alloc(drv, sizeof(*dev));
55 if (!dev) {
56 comp_cl_err(drv, "codec_adapter_new(), failed to allocate memory for comp_dev");
57 return NULL;
58 }
59 dev->ipc_config = *config;
60 dev->drv = drv;
61
62 cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
63 if (!cd) {
64 comp_err(dev, "codec_adapter_new(), failed to allocate memory for comp_data");
65 rfree(dev);
66 return NULL;
67 }
68
69 comp_set_drvdata(dev, cd);
70
71 /* Copy setup config */
72 ret = load_setup_config(dev, ipc_codec_adapter->data, ipc_codec_adapter->size);
73 if (ret) {
74 comp_err(dev, "codec_adapter_new() error %d: config loading has failed.",
75 ret);
76 goto err;
77 }
78 /* Init processing codec */
79 ret = codec_init(dev, interface);
80 if (ret) {
81 comp_err(dev, "codec_adapter_new() %d: codec initialization failed",
82 ret);
83 goto err;
84 }
85
86 dev->state = COMP_STATE_READY;
87
88 comp_dbg(dev, "codec_adapter_new() done");
89 return dev;
90 err:
91 rfree(cd);
92 rfree(dev);
93 return NULL;
94 }
95
validate_setup_config(struct ca_config * cfg)96 int validate_setup_config(struct ca_config *cfg)
97 {
98 /* TODO: validate codec_adapter setup parameters */
99 return 0;
100 }
101
102 /**
103 * \brief Load setup config for both codec adapter and codec library.
104 * \param[in] dev - codec adapter component device pointer.
105 * \param[in] cfg - pointer to the configuration data.
106 * \param[in] size - size of config.
107 *
108 * The setup config comprises of two parts - one contains essential data
109 * for the initialization of codec_adapter and follows struct ca_config.
110 * Second contains codec specific data needed to setup the codec itself.
111 * The latter is send in a TLV format organized by struct codec_param.
112 *
113 * \return integer representing either:
114 * 0 -> success
115 * negative value -> failure.
116 */
load_setup_config(struct comp_dev * dev,void * cfg,uint32_t size)117 int load_setup_config(struct comp_dev *dev, void *cfg, uint32_t size)
118 {
119 int ret;
120 void *lib_cfg;
121 size_t lib_cfg_size;
122 struct comp_data *cd = comp_get_drvdata(dev);
123
124 comp_dbg(dev, "load_setup_config() start.");
125
126 if (!dev) {
127 comp_err(dev, "load_setup_config(): no component device.");
128 ret = -EINVAL;
129 goto end;
130 } else if (!cfg || !size) {
131 comp_err(dev, "load_setup_config(): no config available cfg: %x, size: %d",
132 (uintptr_t)cfg, size);
133 ret = -EINVAL;
134 goto end;
135 } else if (size < sizeof(struct ca_config)) {
136 comp_err(dev, "load_setup_config(): no codec config available, size %d", size);
137 ret = -EIO;
138 goto end;
139 }
140 /* Copy codec_adapter part */
141 ret = memcpy_s(&cd->ca_config, sizeof(cd->ca_config), cfg,
142 sizeof(struct ca_config));
143 assert(!ret);
144 ret = validate_setup_config(&cd->ca_config);
145 if (ret) {
146 comp_err(dev, "load_setup_config(): validation of setup config for codec_adapter failed.");
147 goto end;
148 }
149 /* Copy codec specific part */
150 lib_cfg_size = size - sizeof(struct ca_config);
151 if (lib_cfg_size) {
152 lib_cfg = (char *)cfg + sizeof(struct ca_config);
153 ret = codec_load_config(dev, lib_cfg, lib_cfg_size, CODEC_CFG_SETUP);
154 if (ret) {
155 comp_err(dev, "load_setup_config(): %d: failed to load setup config for codec id %x",
156 ret, cd->ca_config.codec_id);
157 goto end;
158 }
159 }
160
161 comp_dbg(dev, "load_setup_config() done.");
162 end:
163 return ret;
164 }
165
166 /*
167 * \brief Prepare a codec adapter component.
168 * \param[in] dev - component device pointer.
169 *
170 * \return integer representing either:
171 * 0 - success
172 * value < 0 - failure.
173 */
codec_adapter_prepare(struct comp_dev * dev)174 int codec_adapter_prepare(struct comp_dev *dev)
175 {
176 int ret;
177 struct comp_data *cd = comp_get_drvdata(dev);
178 struct codec_data *codec = &cd->codec;
179 uint32_t buff_periods = 2; /* default periods of local buffer,
180 * may change if case of deep buffering
181 */
182 uint32_t buff_size; /* size of local buffer */
183
184 comp_dbg(dev, "codec_adapter_prepare() start");
185
186 /* Init sink & source buffers */
187 cd->ca_sink = list_first_item(&dev->bsink_list, struct comp_buffer,
188 source_list);
189 cd->ca_source = list_first_item(&dev->bsource_list, struct comp_buffer,
190 sink_list);
191
192 if (!cd->ca_source) {
193 comp_err(dev, "codec_adapter_prepare(): source buffer not found");
194 return -EINVAL;
195 } else if (!cd->ca_sink) {
196 comp_err(dev, "codec_adapter_prepare(): sink buffer not found");
197 return -EINVAL;
198 }
199
200 /* Are we already prepared? */
201 ret = comp_set_state(dev, COMP_TRIGGER_PREPARE);
202 if (ret < 0)
203 return ret;
204
205 if (ret == COMP_STATUS_STATE_ALREADY_SET) {
206 comp_warn(dev, "codec_adapter_prepare(): codec_adapter has already been prepared");
207 return PPL_STATUS_PATH_STOP;
208 }
209
210 /* Prepare codec */
211 ret = codec_prepare(dev);
212 if (ret) {
213 comp_err(dev, "codec_adapter_prepare() error %x: codec prepare failed",
214 ret);
215
216 return -EIO;
217 }
218
219 /* Codec is prepared, now we need to configure processing settings.
220 * If codec internal buffer is not equal to natural multiple of pipeline
221 * buffer we have a situation where CA have to deep buffer certain amount
222 * of samples on its start (typically few periods) in order to regularly
223 * generate output once started (same situation happens for compress streams
224 * as well).
225 */
226 if (codec->cpd.in_buff_size != cd->period_bytes) {
227 if (codec->cpd.in_buff_size > cd->period_bytes) {
228 buff_periods = (codec->cpd.in_buff_size % cd->period_bytes) ?
229 (codec->cpd.in_buff_size / cd->period_bytes) + 2 :
230 (codec->cpd.in_buff_size / cd->period_bytes) + 1;
231 } else {
232 buff_periods = (cd->period_bytes % codec->cpd.in_buff_size) ?
233 (cd->period_bytes / codec->cpd.in_buff_size) + 2 :
234 (cd->period_bytes / codec->cpd.in_buff_size) + 1;
235 }
236
237 cd->deep_buff_bytes = cd->period_bytes * buff_periods;
238 } else {
239 cd->deep_buff_bytes = 0;
240 }
241
242 /* Allocate local buffer */
243 buff_size = MAX(cd->period_bytes, codec->cpd.out_buff_size) * buff_periods;
244 if (cd->local_buff) {
245 ret = buffer_set_size(cd->local_buff, buff_size);
246 if (ret < 0) {
247 comp_err(dev, "codec_adapter_prepare(): buffer_set_size() failed, buff_size = %u",
248 buff_size);
249 return ret;
250 }
251 } else {
252 cd->local_buff = buffer_alloc(buff_size, SOF_MEM_CAPS_RAM,
253 PLATFORM_DCACHE_ALIGN);
254 if (!cd->local_buff) {
255 comp_err(dev, "codec_adapter_prepare(): failed to allocate local buffer");
256 return -ENOMEM;
257 }
258
259 }
260 buffer_set_params(cd->local_buff, &cd->stream_params,
261 BUFFER_UPDATE_FORCE);
262 buffer_reset_pos(cd->local_buff, NULL);
263
264 comp_dbg(dev, "codec_adapter_prepare() done");
265
266 return 0;
267 }
268
codec_adapter_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)269 int codec_adapter_params(struct comp_dev *dev,
270 struct sof_ipc_stream_params *params)
271 {
272 int ret;
273 struct comp_data *cd = comp_get_drvdata(dev);
274
275 ret = comp_verify_params(dev, 0, params);
276 if (ret < 0) {
277 comp_err(dev, "codec_adapter_params(): comp_verify_params() failed.");
278 return ret;
279 }
280
281 ret = memcpy_s(&cd->stream_params, sizeof(struct sof_ipc_stream_params),
282 params, sizeof(struct sof_ipc_stream_params));
283 assert(!ret);
284
285 cd->period_bytes = params->sample_container_bytes *
286 params->channels * params->rate / 1000;
287 return 0;
288 }
289
290 static void
codec_adapter_copy_from_source_to_lib(const struct audio_stream * source,const struct codec_processing_data * cpd,size_t bytes)291 codec_adapter_copy_from_source_to_lib(const struct audio_stream *source,
292 const struct codec_processing_data *cpd,
293 size_t bytes)
294 {
295 /* head_size - available data until end of local buffer */
296 const int without_wrap = audio_stream_bytes_without_wrap(source, source->r_ptr);
297 uint32_t head_size = MIN(bytes, without_wrap);
298 /* tail_size - residue data to be copied starting from the beginning
299 * of the buffer
300 */
301 uint32_t tail_size = bytes - head_size;
302 /* copy head_size to lib buffer */
303 memcpy_s(cpd->in_buff, cpd->in_buff_size, source->r_ptr, head_size);
304 if (tail_size)
305 /* copy reset of the samples after wrap-up */
306 memcpy_s((char *)cpd->in_buff + head_size, cpd->in_buff_size,
307 audio_stream_wrap(source,
308 (char *)source->r_ptr + head_size),
309 tail_size);
310 }
311
312 static void
codec_adapter_copy_from_lib_to_sink(const struct codec_processing_data * cpd,const struct audio_stream * sink,size_t bytes)313 codec_adapter_copy_from_lib_to_sink(const struct codec_processing_data *cpd,
314 const struct audio_stream *sink,
315 size_t bytes)
316 {
317 /* head_size - free space until end of local buffer */
318 const int without_wrap =
319 audio_stream_bytes_without_wrap(sink, sink->w_ptr);
320 uint32_t head_size = MIN(bytes, without_wrap);
321 /* tail_size - rest of the bytes that needs to be written
322 * starting from the beginning of the buffer
323 */
324 uint32_t tail_size = bytes - head_size;
325
326 /* copy head_size to sink buffer */
327 memcpy_s(sink->w_ptr, sink->size, cpd->out_buff, head_size);
328 if (tail_size)
329 /* copy reset of the samples after wrap-up */
330 memcpy_s(audio_stream_wrap(sink,
331 (char *)sink->w_ptr + head_size),
332 sink->size,
333 (char *)cpd->out_buff + head_size, tail_size);
334 }
335
336 /**
337 * \brief Generate zero samples of "bytes" size for the sink.
338 * \param[in] sink - a pointer to sink buffer.
339 * \param[in] bytes - number of zero bytes to produce.
340 *
341 * \return: none.
342 */
generate_zeroes(struct comp_buffer * sink,uint32_t bytes)343 static void generate_zeroes(struct comp_buffer *sink, uint32_t bytes)
344 {
345 uint32_t tmp, copy_bytes = bytes;
346 void *ptr;
347
348 while (copy_bytes) {
349 ptr = audio_stream_wrap(&sink->stream, sink->stream.w_ptr);
350 tmp = audio_stream_bytes_without_wrap(&sink->stream,
351 ptr);
352 tmp = MIN(tmp, copy_bytes);
353 ptr = (char *)ptr + tmp;
354 copy_bytes -= tmp;
355 }
356 comp_update_buffer_produce(sink, bytes);
357 }
358
get_output_bytes(struct comp_dev * dev)359 static int get_output_bytes(struct comp_dev *dev)
360 {
361 struct comp_data *cd = comp_get_drvdata(dev);
362
363 return codec_get_samples(dev) * cd->stream_params.sample_container_bytes *
364 cd->stream_params.channels;
365 }
366
codec_adapter_copy(struct comp_dev * dev)367 int codec_adapter_copy(struct comp_dev *dev)
368 {
369 int ret = 0;
370 uint32_t bytes_to_process, copy_bytes, processed = 0, produced = 0;
371 struct comp_data *cd = comp_get_drvdata(dev);
372 struct codec_data *codec = &cd->codec;
373 struct comp_buffer *source = cd->ca_source;
374 struct comp_buffer *sink = cd->ca_sink;
375 uint32_t codec_buff_size = codec->cpd.in_buff_size;
376 struct comp_buffer *local_buff = cd->local_buff;
377 struct comp_copy_limits cl;
378
379 comp_get_copy_limits_with_lock(source, local_buff, &cl);
380 bytes_to_process = cl.frames * cl.source_frame_bytes;
381
382 comp_dbg(dev, "codec_adapter_copy() start: codec_buff_size: %d, local_buff free: %d source avail %d",
383 codec_buff_size, local_buff->stream.free, source->stream.avail);
384
385 if (!codec->cpd.init_done) {
386 if (bytes_to_process < codec_buff_size)
387 goto db_verify;
388
389 buffer_invalidate(source, codec_buff_size);
390 codec_adapter_copy_from_source_to_lib(&source->stream, &codec->cpd,
391 codec_buff_size);
392 codec->cpd.avail = codec_buff_size;
393 ret = codec_init_process(dev);
394 if (ret)
395 return ret;
396
397 bytes_to_process -= codec->cpd.consumed;
398 processed += codec->cpd.consumed;
399 comp_update_buffer_consume(source, codec->cpd.consumed);
400 }
401
402 /* Proceed only if we have enough data to fill the lib buffer
403 * completely. If you don't fill whole buffer
404 * the lib won't process it.
405 */
406 if (bytes_to_process < codec_buff_size) {
407 comp_dbg(dev, "codec_adapter_copy(): source has less data than codec buffer size - processing terminated.");
408 goto db_verify;
409 }
410
411 /* Process only we have enough free data in the local
412 * buffer. If we don't have enough free space process()
413 * will override the data in the local buffer
414 */
415 if (local_buff->stream.free < get_output_bytes(dev))
416 goto db_verify;
417
418 buffer_invalidate(source, codec_buff_size);
419 codec_adapter_copy_from_source_to_lib(&source->stream, &codec->cpd,
420 codec_buff_size);
421 codec->cpd.avail = codec_buff_size;
422 ret = codec_process(dev);
423 if (ret) {
424 comp_err(dev, "codec_adapter_copy() error %x: lib processing failed",
425 ret);
426 goto db_verify;
427 } else if (codec->cpd.produced == 0) {
428 /* skipping as lib has not produced anything */
429 comp_err(dev, "codec_adapter_copy() error %x: lib hasn't processed anything",
430 ret);
431 goto db_verify;
432 }
433 codec_adapter_copy_from_lib_to_sink(&codec->cpd, &local_buff->stream,
434 codec->cpd.produced);
435
436 bytes_to_process -= codec->cpd.consumed;
437 processed += codec->cpd.consumed;
438 produced += codec->cpd.produced;
439
440 audio_stream_produce(&local_buff->stream, codec->cpd.produced);
441 comp_update_buffer_consume(source, codec->cpd.consumed);
442
443 db_verify:
444 if (!produced && !cd->deep_buff_bytes) {
445 comp_dbg(dev, "codec_adapter_copy(): nothing processed in this call");
446 /* we haven't produced anything in this period but we
447 * still have data in the local buffer to copy to sink
448 */
449 if (audio_stream_get_avail_bytes(&local_buff->stream) >= cd->period_bytes)
450 goto copy_period;
451 else
452 goto end;
453 }
454
455 if (cd->deep_buff_bytes) {
456 if (cd->deep_buff_bytes >= audio_stream_get_avail_bytes(&local_buff->stream)) {
457 generate_zeroes(sink, cd->period_bytes);
458 goto end;
459 } else {
460 comp_dbg(dev, "codec_adapter_copy(): deep buffering has ended after gathering %d bytes of processed data",
461 audio_stream_get_avail_bytes(&local_buff->stream));
462 cd->deep_buff_bytes = 0;
463 }
464 }
465
466 copy_period:
467 comp_get_copy_limits_with_lock(local_buff, sink, &cl);
468 copy_bytes = cl.frames * cl.source_frame_bytes;
469 audio_stream_copy(&local_buff->stream, 0,
470 &sink->stream, 0,
471 copy_bytes / cd->stream_params.sample_container_bytes);
472 buffer_writeback(sink, copy_bytes);
473
474 comp_update_buffer_produce(sink, copy_bytes);
475 comp_update_buffer_consume(local_buff, copy_bytes);
476 end:
477 comp_dbg(dev, "codec_adapter_copy(): processed %d in this call %d bytes left for next period",
478 processed, bytes_to_process);
479 return ret;
480 }
481
codec_adapter_set_params(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,enum codec_cfg_type type)482 static int codec_adapter_set_params(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata,
483 enum codec_cfg_type type)
484 {
485 int ret;
486 char *dst, *src;
487 static uint32_t size;
488 uint32_t offset;
489 struct comp_data *cd = comp_get_drvdata(dev);
490 struct codec_data *codec = &cd->codec;
491
492 comp_dbg(dev, "codec_adapter_set_params(): start: num_of_elem %d, elem remain %d msg_index %u",
493 cdata->num_elems, cdata->elems_remaining, cdata->msg_index);
494
495 /* Stage 1 verify input params & allocate memory for the config blob */
496 if (cdata->msg_index == 0) {
497 size = cdata->num_elems + cdata->elems_remaining;
498 /* Check that there is no work-in-progress on previous request */
499 if (codec->runtime_params) {
500 comp_err(dev, "codec_adapter_set_params() error: busy with previous request");
501 ret = -EBUSY;
502 goto end;
503 } else if (!size) {
504 comp_err(dev, "codec_adapter_set_params() error: no configuration size %d",
505 size);
506 /* TODO: return -EINVAL. This is temporary until driver fixes its issue */
507 ret = 0;
508 goto end;
509 } else if (size > MAX_BLOB_SIZE) {
510 comp_err(dev, "codec_adapter_set_params() error: blob size is too big cfg size %d, allowed %d",
511 size, MAX_BLOB_SIZE);
512 ret = -EINVAL;
513 goto end;
514 } else if (type != CODEC_CFG_SETUP && type != CODEC_CFG_RUNTIME) {
515 comp_err(dev, "codec_adapter_set_params() error: unknown config type");
516 ret = -EINVAL;
517 goto end;
518 }
519
520 /* Allocate buffer for new params */
521 codec->runtime_params = rballoc(0, SOF_MEM_CAPS_RAM, size);
522 if (!codec->runtime_params) {
523 comp_err(dev, "codec_adapter_set_params(): space allocation for new params failed");
524 ret = -ENOMEM;
525 goto end;
526 }
527
528 memset(codec->runtime_params, 0, size);
529 } else if (!codec->runtime_params) {
530 comp_err(dev, "codec_adapter_set_params() error: no memory available for runtime params in consecutive load");
531 ret = -EIO;
532 goto end;
533 }
534
535 offset = size - (cdata->num_elems + cdata->elems_remaining);
536 dst = (char *)codec->runtime_params + offset;
537 src = (char *)cdata->data->data;
538
539 ret = memcpy_s(dst, size - offset, src, cdata->num_elems);
540 assert(!ret);
541
542 /* Config has been copied now we can load & apply it depending on
543 * codec state.
544 */
545 if (!cdata->elems_remaining) {
546 switch (type) {
547 case CODEC_CFG_SETUP:
548 ret = load_setup_config(dev, codec->runtime_params, size);
549 if (ret) {
550 comp_err(dev, "codec_adapter_set_params(): error %d: load of setup config failed.",
551 ret);
552 } else {
553 comp_dbg(dev, "codec_adapter_set_params() load of setup config done.");
554 }
555
556 break;
557 case CODEC_CFG_RUNTIME:
558 ret = codec_load_config(dev, codec->runtime_params, size,
559 CODEC_CFG_RUNTIME);
560 if (ret) {
561 comp_err(dev, "codec_adapter_set_params() error %d: load of runtime config failed.",
562 ret);
563 goto done;
564 } else {
565 comp_dbg(dev, "codec_adapter_set_params() load of runtime config done.");
566 }
567
568 if (codec->state >= CODEC_INITIALIZED) {
569 /* We are already prepared so we can apply runtime
570 * config right away.
571 */
572 ret = codec_apply_runtime_config(dev);
573 if (ret) {
574 comp_err(dev, "codec_adapter_set_params() error %x: codec runtime config apply failed",
575 ret);
576 } else {
577 comp_dbg(dev, "codec_adapter_set_params() apply of runtime config done.");
578 }
579 } else {
580 cd->codec.r_cfg.avail = true;
581 }
582
583 break;
584 default:
585 comp_err(dev, "codec_adapter_set_params(): error: unknown config type.");
586 break;
587 }
588 } else
589 goto end;
590
591 done:
592 if (codec->runtime_params)
593 rfree(codec->runtime_params);
594 codec->runtime_params = NULL;
595 return ret;
596 end:
597 return ret;
598 }
599
ca_set_binary_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)600 static int ca_set_binary_data(struct comp_dev *dev,
601 struct sof_ipc_ctrl_data *cdata)
602 {
603 int ret;
604
605 comp_dbg(dev, "ca_set_binary_data() start, data type %d", cdata->data->type);
606
607 switch (cdata->data->type) {
608 case CODEC_CFG_SETUP:
609 case CODEC_CFG_RUNTIME:
610 ret = codec_adapter_set_params(dev, cdata, cdata->data->type);
611 break;
612 default:
613 comp_err(dev, "ca_set_binary_data() error: unknown binary data type");
614 ret = -EINVAL;
615 break;
616 }
617
618 return ret;
619 }
620
codec_adapter_ctrl_set_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)621 static int codec_adapter_ctrl_set_data(struct comp_dev *dev,
622 struct sof_ipc_ctrl_data *cdata)
623 {
624 int ret;
625 struct comp_data *cd = comp_get_drvdata(dev);
626
627 comp_dbg(dev, "codec_adapter_ctrl_set_data() start, state %d, cmd %d",
628 cd->codec.state, cdata->cmd);
629
630 /* Check version from ABI header */
631 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
632 comp_err(dev, "codec_adapter_ctrl_set_data(): ABI mismatch!");
633 return -EINVAL;
634 }
635
636 switch (cdata->cmd) {
637 case SOF_CTRL_CMD_ENUM:
638 comp_err(dev, "codec_adapter_ctrl_set_data() set enum is not implemented for codec_adapter.");
639 ret = -EIO;
640 break;
641 case SOF_CTRL_CMD_BINARY:
642 ret = ca_set_binary_data(dev, cdata);
643 break;
644 default:
645 comp_err(dev, "codec_adapter_ctrl_set_data error: unknown set data command");
646 ret = -EINVAL;
647 break;
648 }
649
650 return ret;
651 }
652
653 /* Used to pass standard and bespoke commands (with data) to component */
codec_adapter_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)654 int codec_adapter_cmd(struct comp_dev *dev, int cmd, void *data,
655 int max_data_size)
656 {
657 int ret;
658 struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4);
659
660 comp_dbg(dev, "codec_adapter_cmd() %d start", cmd);
661
662 switch (cmd) {
663 case COMP_CMD_SET_DATA:
664 ret = codec_adapter_ctrl_set_data(dev, cdata);
665 break;
666 case COMP_CMD_GET_DATA:
667 comp_err(dev, "codec_adapter_cmd() get_data not implemented yet.");
668 ret = -ENODATA;
669 break;
670 default:
671 comp_err(dev, "codec_adapter_cmd() error: unknown command");
672 ret = -EINVAL;
673 break;
674 }
675
676 comp_dbg(dev, "codec_adapter_cmd() done");
677 return ret;
678 }
679
codec_adapter_trigger(struct comp_dev * dev,int cmd)680 int codec_adapter_trigger(struct comp_dev *dev, int cmd)
681 {
682 comp_dbg(dev, "codec_adapter_trigger(): component got trigger cmd %x", cmd);
683
684 return comp_set_state(dev, cmd);
685 }
686
codec_adapter_reset(struct comp_dev * dev)687 int codec_adapter_reset(struct comp_dev *dev)
688 {
689 int ret;
690 struct comp_data *cd = comp_get_drvdata(dev);
691
692 comp_dbg(dev, "codec_adapter_reset(): resetting");
693
694 ret = codec_reset(dev);
695 if (ret) {
696 comp_err(dev, "codec_adapter_reset(): error %d, codec reset has failed",
697 ret);
698 }
699 buffer_zero(cd->local_buff);
700
701 comp_dbg(dev, "codec_adapter_reset(): done");
702
703 return comp_set_state(dev, COMP_TRIGGER_RESET);
704 }
705
codec_adapter_free(struct comp_dev * dev)706 void codec_adapter_free(struct comp_dev *dev)
707 {
708 int ret;
709 struct comp_data *cd = comp_get_drvdata(dev);
710
711 comp_dbg(dev, "codec_adapter_free(): start");
712
713 ret = codec_free(dev);
714 if (ret) {
715 comp_err(dev, "codec_adapter_free(): error %d, codec reset has failed",
716 ret);
717 }
718 buffer_free(cd->local_buff);
719 rfree(cd);
720 rfree(dev);
721 }
722