1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2022 Intel Corporation. All rights reserved.
4 //
5 // Author: Jyri Sarha <jyri.sarha@intel.com>
6 
7 #include <sof/audio/module_adapter/module/generic.h>
8 #include <rtos/sof.h>
9 #include <rtos/alloc.h>
10 #include <ipc/topology.h>
11 #include <ipc/control.h>
12 #include <sof/audio/component.h>
13 #include <sof/audio/data_blob.h>
14 
15 LOG_MODULE_REGISTER(data_blob, CONFIG_SOF_LOG_LEVEL);
16 
17 /** \brief Struct handler for large component configs */
18 struct comp_data_blob_handler {
19 	struct comp_dev *dev;	/**< audio component device */
20 	uint32_t data_size;	/**< size of component's data blob */
21 	uint32_t new_data_size;	/**< size of component's new data blob */
22 	void *data;		/**< pointer to data blob */
23 	void *data_new;		/**< pointer to new data blob */
24 	bool data_ready;	/**< set when data blob is fully received */
25 	uint32_t data_pos;	/**< indicates a data position in data
26 				  *  sending/receiving process
27 				  */
28 	uint32_t single_blob:1; /**< Allocate only one blob. Module can not
29 				  *  be active while reconfguring.
30 				  */
31 	void *(*alloc)(size_t size);	/**< alternate allocator, maybe null */
32 	void (*free)(void *buf);	/**< alternate free(), maybe null */
33 
34 	/** validator for new data, maybe null */
35 	int (*validator)(struct comp_dev *dev, void *new_data, uint32_t new_data_size);
36 };
37 
comp_free_data_blob(struct comp_data_blob_handler * blob_handler)38 static void comp_free_data_blob(struct comp_data_blob_handler *blob_handler)
39 {
40 	assert(blob_handler);
41 
42 	if (!blob_handler->data)
43 		return;
44 
45 	blob_handler->free(blob_handler->data);
46 	blob_handler->free(blob_handler->data_new);
47 	blob_handler->data = NULL;
48 	blob_handler->data_new = NULL;
49 	blob_handler->data_size = 0;
50 }
51 
comp_data_blob_set_validator(struct comp_data_blob_handler * blob_handler,int (* validator)(struct comp_dev * dev,void * new_data,uint32_t new_data_size))52 void comp_data_blob_set_validator(struct comp_data_blob_handler *blob_handler,
53 				  int (*validator)(struct comp_dev *dev, void *new_data,
54 						   uint32_t new_data_size))
55 {
56 	assert(blob_handler);
57 
58 	blob_handler->validator = validator;
59 }
60 
comp_get_data_blob(struct comp_data_blob_handler * blob_handler,size_t * size,uint32_t * crc)61 void *comp_get_data_blob(struct comp_data_blob_handler *blob_handler,
62 			 size_t *size, uint32_t *crc)
63 {
64 	assert(blob_handler);
65 
66 	comp_dbg(blob_handler->dev, "comp_get_data_blob()");
67 
68 	if (size)
69 		*size = 0;
70 
71 	/* Function returns new data blob if available */
72 	if (comp_is_new_data_blob_available(blob_handler)) {
73 		comp_dbg(blob_handler->dev, "comp_get_data_blob(): new data available");
74 
75 		/* Free "old" data blob and set data to data_new pointer */
76 		blob_handler->free(blob_handler->data);
77 		blob_handler->data = blob_handler->data_new;
78 		blob_handler->data_size = blob_handler->new_data_size;
79 
80 		blob_handler->data_new = NULL;
81 		blob_handler->data_ready = false;
82 		blob_handler->new_data_size = 0;
83 		blob_handler->data_pos = 0;
84 	}
85 
86 	/* If data is available we calculate crc32 when crc pointer is given */
87 	if (blob_handler->data) {
88 		if (crc)
89 			*crc = crc32(0, blob_handler->data,
90 				     blob_handler->data_size);
91 	} else {
92 		/* If blob_handler->data is equal to NULL and there is no new
93 		 * data blob it means that component hasn't got any config yet.
94 		 * Function returns NULL in that case.
95 		 */
96 		comp_warn(blob_handler->dev, "comp_get_data_blob(): blob_handler->data is not set.");
97 	}
98 
99 	if (size)
100 		*size = blob_handler->data_size;
101 
102 	return blob_handler->data;
103 }
104 
comp_is_new_data_blob_available(struct comp_data_blob_handler * blob_handler)105 bool comp_is_new_data_blob_available(struct comp_data_blob_handler
106 					*blob_handler)
107 {
108 	assert(blob_handler);
109 
110 	comp_dbg(blob_handler->dev, "comp_is_new_data_blob_available()");
111 
112 	/* New data blob is available when new data blob is allocated (data_new
113 	 * is not NULL), and the component has received all required chunks of data
114 	 * (data_ready is set to TRUE)
115 	 */
116 	if (blob_handler->data_new && blob_handler->data_ready)
117 		return true;
118 
119 	return false;
120 }
121 
comp_is_current_data_blob_valid(struct comp_data_blob_handler * blob_handler)122 bool comp_is_current_data_blob_valid(struct comp_data_blob_handler
123 				     *blob_handler)
124 {
125 	return !!blob_handler->data;
126 }
127 
comp_init_data_blob(struct comp_data_blob_handler * blob_handler,uint32_t size,const void * init_data)128 int comp_init_data_blob(struct comp_data_blob_handler *blob_handler,
129 			uint32_t size, const void *init_data)
130 {
131 	int ret;
132 
133 	assert(blob_handler);
134 
135 	comp_free_data_blob(blob_handler);
136 
137 	if (!size)
138 		return 0;
139 
140 	/* Data blob allocation */
141 	blob_handler->data = blob_handler->alloc(size);
142 	if (!blob_handler->data) {
143 		comp_err(blob_handler->dev, "comp_init_data_blob(): model->data allocation failed");
144 		return -ENOMEM;
145 	}
146 
147 	/* If init_data is given, data will be initialized with it. In other
148 	 * case, data will be set to zero.
149 	 */
150 	if (init_data) {
151 		ret = memcpy_s(blob_handler->data, size, init_data, size);
152 		assert(!ret);
153 	} else {
154 		bzero(blob_handler->data, size);
155 	}
156 
157 	blob_handler->data_new = NULL;
158 	blob_handler->data_size = size;
159 	blob_handler->new_data_size = 0;
160 	blob_handler->validator = NULL;
161 
162 	return 0;
163 }
164 
comp_data_blob_set(struct comp_data_blob_handler * blob_handler,enum module_cfg_fragment_position pos,uint32_t data_offset_size,const uint8_t * fragment_in,size_t fragment_size)165 int comp_data_blob_set(struct comp_data_blob_handler *blob_handler,
166 		       enum module_cfg_fragment_position pos, uint32_t data_offset_size,
167 		       const uint8_t *fragment_in, size_t fragment_size)
168 {
169 #if CONFIG_IPC_MAJOR_3
170 	struct sof_ipc_ctrl_data *cdata	= (struct sof_ipc_ctrl_data *)fragment_in;
171 	const uint8_t *fragment = (const uint8_t *)cdata->data[0].data;
172 #elif CONFIG_IPC_MAJOR_4
173 	const uint8_t *fragment = fragment_in;
174 #endif
175 	int ret;
176 
177 	if (!blob_handler)
178 		return -EINVAL;
179 
180 #if CONFIG_IPC_MAJOR_3
181 	if (cdata->cmd != SOF_CTRL_CMD_BINARY) {
182 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), illegal control command");
183 		return -EINVAL;
184 	}
185 #endif
186 
187 	comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd() pos = %d, fragment size = %d",
188 		 pos, fragment_size);
189 
190 	/* Check that there is no work-in-progress previous request */
191 	if (blob_handler->data_new &&
192 	    (pos == MODULE_CFG_FRAGMENT_FIRST || pos == MODULE_CFG_FRAGMENT_SINGLE)) {
193 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), busy with previous request");
194 		return -EBUSY;
195 	}
196 
197 	/* In single blob mode the component can not be reconfigured if the component is active.
198 	 */
199 	if (blob_handler->single_blob && blob_handler->dev->state == COMP_STATE_ACTIVE) {
200 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), on the fly updates forbidden in single blob mode");
201 		return -EBUSY;
202 	}
203 
204 	/* in case when the current package is the first, we should allocate
205 	 * memory for whole model data
206 	 */
207 	if (pos == MODULE_CFG_FRAGMENT_FIRST || pos == MODULE_CFG_FRAGMENT_SINGLE) {
208 		/* in case when required model size is equal to zero we do not
209 		 * allocate memory and should just return 0.
210 		 *
211 		 * Set cmd with cdata->data->size equal to 0 is possible in
212 		 * following situation:
213 		 * 1. At first boot and topology parsing stage, the driver will
214 		 * read all initial values of DSP kcontrols via IPC. Driver send
215 		 * get_model() cmd to components. If we do not initialize
216 		 * component earlier driver will get "model" with size 0.
217 		 * 2. When resuming from runtime suspended, the driver will
218 		 * restore all pipelines and kcontrols, for the tlv binary
219 		 * kcontrols, it will call the set_model() with the cached value
220 		 * and size (0 if it is not updated by any actual end user
221 		 * sof-ctl settings) - basically driver will send set_model()
222 		 * command with size equal to 0.
223 		 */
224 		if (!fragment_size)
225 			return 0;
226 
227 		if (blob_handler->single_blob) {
228 			if (data_offset_size != blob_handler->data_size) {
229 				blob_handler->free(blob_handler->data);
230 				blob_handler->data = NULL;
231 			} else {
232 				blob_handler->data_new = blob_handler->data;
233 				blob_handler->data = NULL;
234 			}
235 		}
236 
237 		if (!blob_handler->data_new) {
238 			blob_handler->data_new = blob_handler->alloc(data_offset_size);
239 			if (!blob_handler->data_new) {
240 				comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): blob_handler->data_new allocation failed.");
241 				return -ENOMEM;
242 			}
243 		}
244 
245 		blob_handler->new_data_size = data_offset_size;
246 		blob_handler->data_ready = false;
247 		blob_handler->data_pos = 0;
248 	}
249 
250 	/* return an error in case when we do not have allocated memory for model data */
251 	if (!blob_handler->data_new) {
252 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): buffer not allocated");
253 		return -ENOMEM;
254 	}
255 
256 	ret = memcpy_s((char *)blob_handler->data_new + blob_handler->data_pos,
257 		       blob_handler->new_data_size - blob_handler->data_pos,
258 		       fragment, fragment_size);
259 	if (ret) {
260 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): failed to copy fragment");
261 		return ret;
262 	}
263 
264 	blob_handler->data_pos += fragment_size;
265 
266 	if (pos == MODULE_CFG_FRAGMENT_SINGLE || pos == MODULE_CFG_FRAGMENT_LAST) {
267 		comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): final package received");
268 		if (blob_handler->validator) {
269 			comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): validating new data...");
270 			ret = blob_handler->validator(blob_handler->dev, blob_handler->data_new,
271 						      blob_handler->new_data_size);
272 			if (ret < 0) {
273 				comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): new data is invalid! discarding it...");
274 				blob_handler->free(blob_handler->data_new);
275 				blob_handler->data_new = NULL;
276 				return ret;
277 			}
278 		}
279 
280 		/* If component state is READY we can omit old
281 		 * configuration immediately. When in playback/capture
282 		 * the new configuration presence is checked in copy().
283 		 */
284 		if (blob_handler->dev->state ==  COMP_STATE_READY) {
285 			blob_handler->free(blob_handler->data);
286 			blob_handler->data = NULL;
287 		}
288 
289 		/* If there is no existing configuration the received
290 		 * can be set to current immediately. It will be
291 		 * applied in prepare() when streaming starts.
292 		 */
293 		if (!blob_handler->data) {
294 			blob_handler->data = blob_handler->data_new;
295 			blob_handler->data_size = blob_handler->new_data_size;
296 
297 			blob_handler->data_new = NULL;
298 
299 			/* The new configuration has been applied */
300 			blob_handler->data_ready = false;
301 			blob_handler->new_data_size = 0;
302 			blob_handler->data_pos = 0;
303 		} else {
304 			/* The new configuration is ready to be applied */
305 			blob_handler->data_ready = true;
306 		}
307 	}
308 
309 	return 0;
310 }
311 
ipc4_comp_data_blob_set(struct comp_data_blob_handler * blob_handler,bool first_block,bool last_block,uint32_t data_offset,const char * data)312 int ipc4_comp_data_blob_set(struct comp_data_blob_handler *blob_handler,
313 			    bool first_block,
314 			    bool last_block,
315 			    uint32_t data_offset,
316 			    const char *data)
317 {
318 	int ret;
319 	int valid_data_size;
320 
321 	assert(blob_handler);
322 
323 	comp_dbg(blob_handler->dev,
324 		 "ipc4_comp_data_blob_set(): data_offset = %d",
325 		 data_offset);
326 
327 	/* in case when the current package is the first, we should allocate
328 	 * memory for whole model data
329 	 */
330 	if (first_block) {
331 		if (!data_offset)
332 			return 0;
333 
334 		if (blob_handler->single_blob) {
335 			if (data_offset != blob_handler->data_size) {
336 				blob_handler->free(blob_handler->data);
337 				blob_handler->data = NULL;
338 			} else {
339 				blob_handler->data_new = blob_handler->data;
340 				blob_handler->data = NULL;
341 			}
342 		}
343 
344 		if (!blob_handler->data_new) {
345 			blob_handler->data_new =
346 				blob_handler->alloc(data_offset);
347 
348 			if (!blob_handler->data_new) {
349 				comp_err(blob_handler->dev,
350 					 "ipc4_comp_data_blob_set(): blob_handler allocation failed!");
351 				return -ENOMEM;
352 			}
353 		}
354 
355 		blob_handler->new_data_size = data_offset;
356 		blob_handler->data_ready = false;
357 		blob_handler->data_pos = 0;
358 
359 		valid_data_size = last_block ? data_offset : MAILBOX_DSPBOX_SIZE;
360 
361 		ret = memcpy_s((char *)blob_handler->data_new,
362 			       valid_data_size, data, valid_data_size);
363 		assert(!ret);
364 
365 		blob_handler->data_pos += valid_data_size;
366 	} else {
367 		/* return an error in case when we do not have allocated memory for
368 		 * model data
369 		 */
370 		if (!blob_handler->data_new) {
371 			comp_err(blob_handler->dev,
372 				 "ipc4_comp_data_blob_set(): Buffer not allocated!");
373 			return -ENOMEM;
374 		}
375 
376 		if (blob_handler->data_pos != data_offset) {
377 			comp_err(blob_handler->dev,
378 				 "ipc4_comp_data_blob_set(): Wrong data offset received!");
379 			return -EINVAL;
380 		}
381 
382 		valid_data_size = MAILBOX_DSPBOX_SIZE;
383 
384 		if (last_block)
385 			valid_data_size = blob_handler->new_data_size - data_offset;
386 
387 		ret = memcpy_s((char *)blob_handler->data_new + data_offset,
388 			       valid_data_size, data, valid_data_size);
389 		assert(!ret);
390 
391 		blob_handler->data_pos += valid_data_size;
392 	}
393 
394 	if (last_block) {
395 		comp_dbg(blob_handler->dev,
396 			 "ipc4_comp_data_blob_set(): final package received");
397 
398 		/* If component state is READY we can omit old
399 		 * configuration immediately. When in playback/capture
400 		 * the new configuration presence is checked in copy().
401 		 */
402 		if (blob_handler->dev->state ==  COMP_STATE_READY) {
403 			blob_handler->free(blob_handler->data);
404 			blob_handler->data = NULL;
405 		}
406 
407 		/* If there is no existing configuration the received
408 		 * can be set to current immediately. It will be
409 		 * applied in prepare() when streaming starts.
410 		 */
411 		if (!blob_handler->data) {
412 			blob_handler->data = blob_handler->data_new;
413 			blob_handler->data_size = blob_handler->new_data_size;
414 
415 			blob_handler->data_new = NULL;
416 
417 			/* The new configuration has been applied */
418 			blob_handler->data_ready = false;
419 			blob_handler->new_data_size = 0;
420 			blob_handler->data_pos = 0;
421 		} else {
422 			/* The new configuration is ready to be applied */
423 			blob_handler->data_ready = true;
424 		}
425 	}
426 
427 	return 0;
428 }
429 
comp_data_blob_set_cmd(struct comp_data_blob_handler * blob_handler,struct sof_ipc_ctrl_data * cdata)430 int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler,
431 			   struct sof_ipc_ctrl_data *cdata)
432 {
433 	int ret = 0;
434 
435 	assert(blob_handler);
436 
437 	comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd() msg_index = %d, num_elems = %d, remaining = %d ",
438 		 cdata->msg_index, cdata->num_elems,
439 		 cdata->elems_remaining);
440 
441 	/* Check that there is no work-in-progress previous request */
442 	if (blob_handler->data_new && cdata->msg_index == 0) {
443 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), busy with previous request");
444 		return -EBUSY;
445 	}
446 
447 	/* In single blob mode the component can not be reconfigured if
448 	 * the component is active.
449 	 */
450 	if (blob_handler->single_blob &&
451 	    blob_handler->dev->state == COMP_STATE_ACTIVE) {
452 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), on the fly updates forbidden in single blob mode");
453 		return -EBUSY;
454 	}
455 
456 	/* in case when the current package is the first, we should allocate
457 	 * memory for whole model data
458 	 */
459 	if (!cdata->msg_index) {
460 		/* in case when required model size is equal to zero we do not
461 		 * allocate memory and should just return 0.
462 		 *
463 		 * Set cmd with cdata->data->size equal to 0 is possible in
464 		 * following situation:
465 		 * 1. At first boot and topology parsing stage, the driver will
466 		 * read all initial values of DSP kcontrols via IPC. Driver send
467 		 * get_model() cmd to components. If we do not initialize
468 		 * component earlier driver will get "model" with size 0.
469 		 * 2. When resuming from runtime suspended, the driver will
470 		 * restore all pipelines and kcontrols, for the tlv binary
471 		 * kcontrols, it will call the set_model() with the cached value
472 		 * and size (0 if it is not updated by any actual end user
473 		 * sof-ctl settings) - basically driver will send set_model()
474 		 * command with size equal to 0.
475 		 */
476 		if (!cdata->data->size)
477 			return 0;
478 
479 		if (blob_handler->single_blob) {
480 			if (cdata->data->size != blob_handler->data_size) {
481 				blob_handler->free(blob_handler->data);
482 				blob_handler->data = NULL;
483 			} else {
484 				blob_handler->data_new = blob_handler->data;
485 				blob_handler->data = NULL;
486 			}
487 		}
488 
489 		if (!blob_handler->data_new) {
490 			blob_handler->data_new =
491 				blob_handler->alloc(cdata->data->size);
492 			if (!blob_handler->data_new) {
493 				comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): blob_handler->data_new allocation failed.");
494 				return -ENOMEM;
495 			}
496 		}
497 
498 		blob_handler->new_data_size = cdata->data->size;
499 		blob_handler->data_ready = false;
500 		blob_handler->data_pos = 0;
501 	}
502 
503 	/* return an error in case when we do not have allocated memory for
504 	 * model data
505 	 */
506 	if (!blob_handler->data_new) {
507 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): buffer not allocated");
508 		return -ENOMEM;
509 	}
510 
511 	ret = memcpy_s((char *)blob_handler->data_new + blob_handler->data_pos,
512 		       blob_handler->new_data_size - blob_handler->data_pos,
513 		       cdata->data->data, cdata->num_elems);
514 	assert(!ret);
515 
516 	blob_handler->data_pos += cdata->num_elems;
517 
518 	if (!cdata->elems_remaining) {
519 		comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): final package received");
520 
521 		if (blob_handler->validator) {
522 			comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): validating new data blob");
523 			ret = blob_handler->validator(blob_handler->dev, blob_handler->data_new,
524 						      blob_handler->new_data_size);
525 			if (ret < 0) {
526 				comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): new data blob invalid, discarding");
527 				blob_handler->free(blob_handler->data_new);
528 				blob_handler->data_new = NULL;
529 				return ret;
530 			}
531 		}
532 
533 		/* If component state is READY we can omit old
534 		 * configuration immediately. When in playback/capture
535 		 * the new configuration presence is checked in copy().
536 		 */
537 		if (blob_handler->dev->state ==  COMP_STATE_READY) {
538 			blob_handler->free(blob_handler->data);
539 			blob_handler->data = NULL;
540 		}
541 
542 		/* If there is no existing configuration the received
543 		 * can be set to current immediately. It will be
544 		 * applied in prepare() when streaming starts.
545 		 */
546 		if (!blob_handler->data) {
547 			blob_handler->data = blob_handler->data_new;
548 			blob_handler->data_size = blob_handler->new_data_size;
549 
550 			blob_handler->data_new = NULL;
551 
552 			/* The new configuration has been applied */
553 			blob_handler->data_ready = false;
554 			blob_handler->new_data_size = 0;
555 			blob_handler->data_pos = 0;
556 		} else {
557 			/* The new configuration is ready to be applied */
558 			blob_handler->data_ready = true;
559 		}
560 	}
561 
562 	return 0;
563 }
564 
comp_data_blob_get_cmd(struct comp_data_blob_handler * blob_handler,struct sof_ipc_ctrl_data * cdata,int size)565 int comp_data_blob_get_cmd(struct comp_data_blob_handler *blob_handler,
566 			   struct sof_ipc_ctrl_data *cdata, int size)
567 {
568 	int ret = 0;
569 
570 	assert(blob_handler);
571 
572 	if (cdata->cmd != SOF_CTRL_CMD_BINARY) {
573 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), illegal control command");
574 		return -EINVAL;
575 	}
576 
577 	comp_dbg(blob_handler->dev, "comp_data_blob_get_cmd() msg_index = %d, num_elems = %d, remaining = %d ",
578 		 cdata->msg_index, cdata->num_elems,
579 		 cdata->elems_remaining);
580 
581 	/* Copy back to user space */
582 	if (blob_handler->data) {
583 		/* reset data_pos variable in case of copying first element */
584 		if (!cdata->msg_index) {
585 			blob_handler->data_pos = 0;
586 			comp_dbg(blob_handler->dev, "comp_data_blob_get_cmd() model data_size = 0x%x",
587 				 blob_handler->data_size);
588 		}
589 
590 		/* return an error in case of mismatch between num_elems and
591 		 * required size
592 		 */
593 		if (cdata->num_elems > size) {
594 			comp_err(blob_handler->dev, "comp_data_blob_get_cmd(): invalid cdata->num_elems %d",
595 				 cdata->num_elems);
596 			return -EINVAL;
597 		}
598 
599 		/* copy required size of data */
600 		ret = memcpy_s(cdata->data->data, size,
601 			       (char *)blob_handler->data + blob_handler->data_pos,
602 			       cdata->num_elems);
603 		assert(!ret);
604 
605 		cdata->data->abi = SOF_ABI_VERSION;
606 		cdata->data->size = blob_handler->data_size;
607 		blob_handler->data_pos += cdata->num_elems;
608 	} else {
609 		comp_warn(blob_handler->dev, "comp_data_blob_get_cmd(): model->data not allocated yet.");
610 		cdata->data->abi = SOF_ABI_VERSION;
611 		cdata->data->size = 0;
612 	}
613 
614 	return ret;
615 }
616 
default_alloc(size_t size)617 static void *default_alloc(size_t size)
618 {
619 	return rballoc(0, SOF_MEM_CAPS_RAM, size);
620 }
621 
default_free(void * buf)622 static void default_free(void *buf)
623 {
624 	rfree(buf);
625 }
626 
627 struct comp_data_blob_handler *
comp_data_blob_handler_new_ext(struct comp_dev * dev,bool single_blob,void * (* alloc)(size_t size),void (* free)(void * buf))628 comp_data_blob_handler_new_ext(struct comp_dev *dev, bool single_blob,
629 			       void *(*alloc)(size_t size),
630 			       void (*free)(void *buf))
631 {
632 	struct comp_data_blob_handler *handler;
633 
634 	comp_dbg(dev, "comp_data_blob_handler_new_ext()");
635 
636 	handler = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM,
637 			  sizeof(struct comp_data_blob_handler));
638 
639 	if (handler) {
640 		handler->dev = dev;
641 		handler->single_blob = single_blob;
642 		handler->alloc = alloc ? alloc : default_alloc;
643 		handler->free = free ? free : default_free;
644 	}
645 
646 	return handler;
647 }
648 
comp_data_blob_handler_free(struct comp_data_blob_handler * blob_handler)649 void comp_data_blob_handler_free(struct comp_data_blob_handler *blob_handler)
650 {
651 	if (!blob_handler)
652 		return;
653 
654 	comp_free_data_blob(blob_handler);
655 
656 	rfree(blob_handler);
657 }
658