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