1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4 
5 /* file component for reading/writing pcm samples to/from a file */
6 
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stddef.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <inttypes.h>
13 #include <sof/sof.h>
14 #include <sof/list.h>
15 #include <sof/audio/stream.h>
16 #include <sof/audio/ipc-config.h>
17 #include <sof/lib/clk.h>
18 #include <sof/ipc/driver.h>
19 #include <sof/audio/component.h>
20 #include <sof/audio/format.h>
21 #include <sof/audio/pipeline.h>
22 #include <ipc/stream.h>
23 #include "testbench/common_test.h"
24 #include "testbench/file.h"
25 
26 /* bfc7488c-75aa-4ce8-9bde-d8da08a698c2 */
27 DECLARE_SOF_UUID("file", file_uuid, 0xbfc7488c, 0x75aa, 0x4ce8,
28 		 0x9d, 0xbe, 0xd8, 0xda, 0x08, 0xa6, 0x98, 0xc2);
29 DECLARE_TR_CTX(file_tr, SOF_UUID(file_uuid), LOG_LEVEL_INFO);
30 
31 static const struct comp_driver comp_file_dai;
32 static const struct comp_driver comp_file_host;
33 
buffer_check_wrap_32(int32_t ** ptr,int32_t * end,size_t size)34 static inline void buffer_check_wrap_32(int32_t **ptr, int32_t *end,
35 					size_t size)
36 {
37 	if (*ptr >= end)
38 		*ptr = (int32_t *)((size_t)*ptr - size);
39 }
40 
buffer_check_wrap_16(int16_t ** ptr,int16_t * end,size_t size)41 static inline void buffer_check_wrap_16(int16_t **ptr, int16_t *end,
42 					size_t size)
43 {
44 	if (*ptr >= end)
45 		*ptr = (int16_t *)((size_t)*ptr - size);
46 }
47 
48 /*
49  * Read 32-bit samples from file
50  * currently only supports txt files
51  */
read_samples_32(struct comp_dev * dev,const struct audio_stream * sink,int n,int fmt,int nch)52 static int read_samples_32(struct comp_dev *dev,
53 			   const struct audio_stream *sink,
54 			   int n, int fmt, int nch)
55 {
56 	struct file_comp_data *cd = comp_get_drvdata(dev);
57 	int32_t *dest = (int32_t *)sink->w_ptr;
58 	int32_t sample;
59 	int n_wrap;
60 	int n_min;
61 	int i;
62 	int n_samples = 0;
63 	int ret = 0;
64 
65 	while (n > 0) {
66 		n_wrap = (int32_t *)sink->end_addr - dest;
67 
68 		/* check for buffer wrap and copy to the end of the buffer */
69 		n_min = (n < n_wrap) ? n : n_wrap;
70 		while (n_min > 0) {
71 			n -= nch;
72 			n_min -= nch;
73 
74 			/* copy sample per channel */
75 			for (i = 0; i < nch; i++) {
76 				/* read sample from file */
77 				switch (cd->fs.f_format) {
78 				/* text input file */
79 				case FILE_TEXT:
80 					if (fmt == SOF_IPC_FRAME_S32_LE)
81 						ret = fscanf(cd->fs.rfh, "%d",
82 							     dest);
83 
84 					/* mask bits if 24-bit samples */
85 					if (fmt == SOF_IPC_FRAME_S24_4LE) {
86 						ret = fscanf(cd->fs.rfh, "%d",
87 							     &sample);
88 						*dest = sample & 0x00ffffff;
89 					}
90 					/* quit if eof is reached */
91 					if (ret == EOF) {
92 						cd->fs.reached_eof = 1;
93 						goto quit;
94 					}
95 					break;
96 
97 				/* raw input file */
98 				default:
99 					if (fmt == SOF_IPC_FRAME_S32_LE)
100 						ret = fread(dest,
101 							    sizeof(int32_t),
102 							    1, cd->fs.rfh);
103 
104 					/* mask bits if 24-bit samples */
105 					if (fmt == SOF_IPC_FRAME_S24_4LE) {
106 						ret = fread(&sample,
107 							    sizeof(int32_t),
108 							    1, cd->fs.rfh);
109 						*dest = sample & 0x00ffffff;
110 					}
111 					/* quit if eof is reached */
112 					if (ret != 1) {
113 						cd->fs.reached_eof = 1;
114 						goto quit;
115 					}
116 					break;
117 				}
118 				dest++;
119 				n_samples++;
120 			}
121 		}
122 		/* check for buffer wrap and update pointer */
123 		buffer_check_wrap_32(&dest, sink->end_addr,
124 				     sink->size);
125 	}
126 quit:
127 	return n_samples;
128 }
129 
130 /*
131  * Read 16-bit samples from file
132  * currently only supports txt files
133  */
read_samples_16(struct comp_dev * dev,const struct audio_stream * sink,int n,int nch)134 static int read_samples_16(struct comp_dev *dev,
135 			   const struct audio_stream *sink,
136 			   int n, int nch)
137 {
138 	struct file_comp_data *cd = comp_get_drvdata(dev);
139 	int16_t *dest = (int16_t *)sink->w_ptr;
140 	int i, n_wrap, n_min, ret;
141 	int n_samples = 0;
142 
143 	/* copy samples */
144 	while (n > 0) {
145 		n_wrap = (int16_t *)sink->end_addr - dest;
146 
147 		/* check for buffer wrap and copy to the end of the buffer */
148 		n_min = (n < n_wrap) ? n : n_wrap;
149 		while (n_min > 0) {
150 			n -= nch;
151 			n_min -= nch;
152 
153 			/* copy sample per channel */
154 			for (i = 0; i < nch; i++) {
155 				switch (cd->fs.f_format) {
156 				/* text input file */
157 				case FILE_TEXT:
158 					ret = fscanf(cd->fs.rfh, "%hd", dest);
159 					if (ret == EOF) {
160 						cd->fs.reached_eof = 1;
161 						goto quit;
162 					}
163 					break;
164 
165 				/* rw pcm input file */
166 				default:
167 					ret = fread(dest, sizeof(int16_t), 1,
168 						    cd->fs.rfh);
169 					if (ret != 1) {
170 						cd->fs.reached_eof = 1;
171 						goto quit;
172 					}
173 					break;
174 				}
175 
176 				dest++;
177 				n_samples++;
178 			}
179 		}
180 		/* check for buffer wrap and update pointer */
181 		buffer_check_wrap_16(&dest, sink->end_addr,
182 				     sink->size);
183 	}
184 
185 quit:
186 	return n_samples;
187 }
188 
189 /*
190  * Write 16-bit samples from file
191  * currently only supports txt files
192  */
write_samples_16(struct comp_dev * dev,struct audio_stream * source,int n,int nch)193 static int write_samples_16(struct comp_dev *dev, struct audio_stream *source,
194 			    int n, int nch)
195 {
196 	struct file_comp_data *cd = comp_get_drvdata(dev);
197 	int16_t *src = (int16_t *)source->r_ptr;
198 	int i, n_wrap, n_min, ret;
199 	int n_samples = 0;
200 
201 	/* copy samples */
202 	while (n > 0) {
203 		n_wrap = (int16_t *)source->end_addr - src;
204 
205 		/* check for buffer wrap and copy to the end of the buffer */
206 		n_min = (n < n_wrap) ? n : n_wrap;
207 		while (n_min > 0) {
208 			n -= nch;
209 			n_min -= nch;
210 
211 			/* copy sample per channel */
212 			for (i = 0; i < nch; i++) {
213 				switch (cd->fs.f_format) {
214 				/* text output file */
215 				case FILE_TEXT:
216 					ret = fprintf(cd->fs.wfh,
217 						      "%d\n", *src);
218 					if (ret < 0)
219 						goto quit;
220 					break;
221 
222 				/* raw pcm output file */
223 				default:
224 					ret = fwrite(src,
225 						     sizeof(int16_t),
226 						     1, cd->fs.wfh);
227 					if (ret != 1)
228 						goto quit;
229 					break;
230 				}
231 
232 				src++;
233 				n_samples++;
234 			}
235 		}
236 		/* check for buffer wrap and update pointer */
237 		buffer_check_wrap_16(&src, source->end_addr,
238 				     source->size);
239 	}
240 quit:
241 	return n_samples;
242 }
243 
244 /*
245  * Write 32-bit samples from file
246  * currently only supports txt files
247  */
write_samples_32(struct comp_dev * dev,struct audio_stream * source,int n,int fmt,int nch)248 static int write_samples_32(struct comp_dev *dev, struct audio_stream *source,
249 			    int n, int fmt, int nch)
250 {
251 	struct file_comp_data *cd = comp_get_drvdata(dev);
252 	int32_t *src = (int32_t *)source->r_ptr;
253 	int i, n_wrap, n_min, ret;
254 	int n_samples = 0;
255 	int32_t sample;
256 
257 	/* copy samples */
258 	while (n > 0) {
259 		n_wrap = (int32_t *)source->end_addr - src;
260 
261 		/* check for buffer wrap and copy to the end of the buffer */
262 		n_min = (n < n_wrap) ? n : n_wrap;
263 		while (n_min > 0) {
264 			n -= nch;
265 			n_min -= nch;
266 
267 			/* copy sample per channel */
268 			for (i = 0; i < nch; i++) {
269 				switch (cd->fs.f_format) {
270 				/* text output file */
271 				case FILE_TEXT:
272 					if (fmt == SOF_IPC_FRAME_S32_LE)
273 						ret = fprintf(cd->fs.wfh,
274 							      "%d\n", *src);
275 					if (fmt == SOF_IPC_FRAME_S24_4LE) {
276 						sample = *src << 8;
277 						ret = fprintf(cd->fs.wfh,
278 							      "%d\n",
279 							      sample >> 8);
280 					}
281 					if (ret < 0)
282 						goto quit;
283 					break;
284 
285 				/* raw pcm output file */
286 				default:
287 					if (fmt == SOF_IPC_FRAME_S32_LE)
288 						ret = fwrite(src,
289 							     sizeof(int32_t),
290 							     1, cd->fs.wfh);
291 					if (fmt == SOF_IPC_FRAME_S24_4LE) {
292 						sample = *src << 8;
293 						sample >>= 8;
294 						ret = fwrite(&sample,
295 							     sizeof(int32_t),
296 							     1, cd->fs.wfh);
297 					}
298 					if (ret != 1)
299 						goto quit;
300 					break;
301 				}
302 
303 				/* increment read pointer */
304 				src++;
305 
306 				/* increment number of samples written */
307 				n_samples++;
308 			}
309 		}
310 		/* check for buffer wrap and update pointer */
311 		buffer_check_wrap_32(&src, source->end_addr,
312 				     source->size);
313 	}
314 quit:
315 	return n_samples;
316 }
317 
318 /* function for processing 32-bit samples */
file_s32_default(struct comp_dev * dev,struct audio_stream * sink,struct audio_stream * source,uint32_t frames)319 static int file_s32_default(struct comp_dev *dev, struct audio_stream *sink,
320 			    struct audio_stream *source, uint32_t frames)
321 {
322 	struct file_comp_data *cd = comp_get_drvdata(dev);
323 	int nch;
324 	int n_samples = 0;
325 
326 	switch (cd->fs.mode) {
327 	case FILE_READ:
328 		/* read samples */
329 		nch = sink->channels;
330 		n_samples = read_samples_32(dev, sink, frames * nch,
331 					    SOF_IPC_FRAME_S32_LE, nch);
332 		break;
333 	case FILE_WRITE:
334 		/* write samples */
335 		nch = source->channels;
336 		n_samples = write_samples_32(dev, source, frames * nch,
337 					     SOF_IPC_FRAME_S32_LE, nch);
338 		break;
339 	default:
340 		/* TODO: duplex mode */
341 		break;
342 	}
343 
344 	cd->fs.n += n_samples;
345 	return n_samples;
346 }
347 
348 /* function for processing 16-bit samples */
file_s16(struct comp_dev * dev,struct audio_stream * sink,struct audio_stream * source,uint32_t frames)349 static int file_s16(struct comp_dev *dev, struct audio_stream *sink,
350 		    struct audio_stream *source, uint32_t frames)
351 {
352 	struct file_comp_data *cd = comp_get_drvdata(dev);
353 	int nch;
354 	int n_samples = 0;
355 
356 	switch (cd->fs.mode) {
357 	case FILE_READ:
358 		/* read samples */
359 		nch = sink->channels;
360 		n_samples = read_samples_16(dev, sink, frames * nch, nch);
361 		break;
362 	case FILE_WRITE:
363 		/* write samples */
364 		nch = source->channels;
365 		n_samples = write_samples_16(dev, source, frames * nch, nch);
366 		break;
367 	default:
368 		/* TODO: duplex mode */
369 		break;
370 	}
371 
372 	cd->fs.n += n_samples;
373 	return n_samples;
374 }
375 
376 /* function for processing 24-bit samples */
file_s24(struct comp_dev * dev,struct audio_stream * sink,struct audio_stream * source,uint32_t frames)377 static int file_s24(struct comp_dev *dev, struct audio_stream *sink,
378 		    struct audio_stream *source, uint32_t frames)
379 {
380 	struct file_comp_data *cd = comp_get_drvdata(dev);
381 	int nch;
382 	int n_samples = 0;
383 
384 	switch (cd->fs.mode) {
385 	case FILE_READ:
386 		/* read samples */
387 		nch = sink->channels;
388 		n_samples = read_samples_32(dev, sink, frames * nch,
389 					    SOF_IPC_FRAME_S24_4LE, nch);
390 		break;
391 	case FILE_WRITE:
392 		/* write samples */
393 		nch = source->channels;
394 		n_samples = write_samples_32(dev, source, frames * nch,
395 					     SOF_IPC_FRAME_S24_4LE, nch);
396 		break;
397 	default:
398 		/* TODO: duplex mode */
399 		break;
400 	}
401 
402 	cd->fs.n += n_samples;
403 	return n_samples;
404 }
405 
get_file_format(char * filename)406 static enum file_format get_file_format(char *filename)
407 {
408 	char *ext = strrchr(filename, '.');
409 
410 	if (!ext)
411 		return FILE_RAW;
412 
413 	if (!strcmp(ext, ".txt"))
414 		return FILE_TEXT;
415 
416 	return FILE_RAW;
417 }
418 
file_new(const struct comp_driver * drv,struct comp_ipc_config * config,void * spec)419 static struct comp_dev *file_new(const struct comp_driver *drv,
420 				 struct comp_ipc_config *config,
421 				 void *spec)
422 {
423 	struct comp_dev *dev;
424 	struct ipc_comp_file *ipc_file = spec;
425 	struct file_comp_data *cd;
426 
427 	debug_print("file_new()\n");
428 
429 
430 	dev = comp_alloc(drv, sizeof(*dev));
431 	if (!dev)
432 		return NULL;
433 	dev->ipc_config = *config;
434 
435 	/* allocate  memory for file comp data */
436 	cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
437 	if (!cd) {
438 		free(dev);
439 		return NULL;
440 	}
441 
442 	comp_set_drvdata(dev, cd);
443 
444 	/* default function for processing samples */
445 	cd->file_func = file_s32_default;
446 
447 	/* get filename from IPC and open file */
448 	cd->fs.fn = strdup(ipc_file->fn);
449 
450 	/* set file format */
451 	cd->fs.f_format = get_file_format(cd->fs.fn);
452 
453 	/* set file comp mode */
454 	cd->fs.mode = ipc_file->mode;
455 
456 	cd->rate = ipc_file->rate;
457 	cd->channels = ipc_file->channels;
458 	cd->frame_fmt = ipc_file->frame_fmt;
459 
460 	/* open file handle(s) depending on mode */
461 	switch (cd->fs.mode) {
462 	case FILE_READ:
463 		cd->fs.rfh = fopen(cd->fs.fn, "r");
464 		if (!cd->fs.rfh) {
465 			fprintf(stderr, "error: opening file %s for reading - %s\n",
466 				cd->fs.fn, strerror(errno));
467 			free(cd);
468 			free(dev);
469 			return NULL;
470 		}
471 		break;
472 	case FILE_WRITE:
473 		cd->fs.wfh = fopen(cd->fs.fn, "w+");
474 		if (!cd->fs.wfh) {
475 			fprintf(stderr, "error: opening file %s for writing - %s\n",
476 				cd->fs.fn, strerror(errno));
477 			free(cd);
478 			free(dev);
479 			return NULL;
480 		}
481 		break;
482 	default:
483 		/* TODO: duplex mode */
484 		break;
485 	}
486 
487 	cd->fs.reached_eof = 0;
488 	cd->fs.n = 0;
489 
490 	dev->state = COMP_STATE_READY;
491 
492 	return dev;
493 }
494 
file_free(struct comp_dev * dev)495 static void file_free(struct comp_dev *dev)
496 {
497 	struct file_comp_data *cd = comp_get_drvdata(dev);
498 
499 	comp_dbg(dev, "file_free()");
500 
501 	if (cd->fs.mode == FILE_READ)
502 		fclose(cd->fs.rfh);
503 	else
504 		fclose(cd->fs.wfh);
505 
506 	free(cd->fs.fn);
507 	free(cd);
508 	free(dev);
509 }
510 
file_verify_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)511 static int file_verify_params(struct comp_dev *dev,
512 			      struct sof_ipc_stream_params *params)
513 {
514 	int ret;
515 
516 	comp_dbg(dev, "file_verify_params()");
517 
518 	ret = comp_verify_params(dev, 0, params);
519 	if (ret < 0) {
520 		comp_err(dev, "file_verify_params() error: comp_verify_params() failed.");
521 		return ret;
522 	}
523 
524 	return 0;
525 }
526 
527 /**
528  * \brief Sets file component audio stream parameters.
529  * \param[in,out] dev Volume base component device.
530  * \param[in] params Audio (PCM) stream parameters (ignored for this component)
531  * \return Error code.
532  *
533  * All done in prepare() since we need to know source and sink component params.
534  */
file_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)535 static int file_params(struct comp_dev *dev,
536 		       struct sof_ipc_stream_params *params)
537 {
538 	int err;
539 
540 	comp_info(dev, "file_params()");
541 
542 	err = file_verify_params(dev, params);
543 	if (err < 0) {
544 		comp_err(dev, "file_params(): pcm params verification failed.");
545 		return -EINVAL;
546 	}
547 
548 	return 0;
549 }
550 
fr_cmd(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)551 static int fr_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
552 {
553 	return -EINVAL;
554 }
555 
file_trigger(struct comp_dev * dev,int cmd)556 static int file_trigger(struct comp_dev *dev, int cmd)
557 {
558 	comp_info(dev, "file_trigger()");
559 	return comp_set_state(dev, cmd);
560 }
561 
562 /* used to pass standard and bespoke commands (with data) to component */
file_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)563 static int file_cmd(struct comp_dev *dev, int cmd, void *data,
564 		    int max_data_size)
565 {
566 	struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4);
567 	int ret = 0;
568 
569 	comp_info(dev, "file_cmd()");
570 	switch (cmd) {
571 	case COMP_CMD_SET_DATA:
572 		ret = fr_cmd(dev, cdata);
573 		break;
574 	default:
575 		break;
576 	}
577 
578 	return ret;
579 }
580 
581 /*
582  * copy and process stream samples
583  * returns the number of bytes copied
584  */
file_copy(struct comp_dev * dev)585 static int file_copy(struct comp_dev *dev)
586 {
587 	struct comp_buffer *buffer;
588 	struct file_comp_data *cd = comp_get_drvdata(dev);
589 	int snk_frames;
590 	int src_frames;
591 	int bytes = cd->sample_container_bytes;
592 	int ret = 0;
593 
594 	switch (cd->fs.mode) {
595 	case FILE_READ:
596 		/* file component sink buffer */
597 		buffer = list_first_item(&dev->bsink_list, struct comp_buffer,
598 					 source_list);
599 
600 		/* test sink has enough free frames */
601 		snk_frames = audio_stream_get_free_frames(&buffer->stream);
602 		if (snk_frames > 0 && !cd->fs.reached_eof) {
603 			/* read PCM samples from file */
604 			ret = cd->file_func(dev, &buffer->stream, NULL,
605 					    snk_frames);
606 
607 			/* update sink buffer pointers */
608 			if (ret > 0)
609 				comp_update_buffer_produce(buffer,
610 							   ret * bytes);
611 		}
612 		break;
613 	case FILE_WRITE:
614 		/* file component source buffer */
615 		buffer = list_first_item(&dev->bsource_list,
616 					 struct comp_buffer, sink_list);
617 
618 		/* test source has enough free frames */
619 		src_frames = audio_stream_get_avail_frames(&buffer->stream);
620 		if (src_frames > 0) {
621 			/* write PCM samples into file */
622 			ret = cd->file_func(dev, NULL, &buffer->stream,
623 					    src_frames);
624 
625 			/* update source buffer pointers */
626 			if (ret > 0)
627 				comp_update_buffer_consume(buffer,
628 							   ret * bytes);
629 		}
630 		break;
631 	default:
632 		/* TODO: duplex mode */
633 		break;
634 	}
635 
636 	return ret;
637 }
638 
file_prepare(struct comp_dev * dev)639 static int file_prepare(struct comp_dev *dev)
640 {
641 	struct comp_buffer *buffer = NULL;
642 	struct file_comp_data *cd = comp_get_drvdata(dev);
643 	struct audio_stream *stream;
644 	int periods;
645 	int ret = 0;
646 
647 	comp_info(dev, "file_prepare()");
648 
649 	ret = comp_set_state(dev, COMP_TRIGGER_PREPARE);
650 	if (ret < 0)
651 		return ret;
652 
653 	if (ret == COMP_STATUS_STATE_ALREADY_SET)
654 		return PPL_STATUS_PATH_STOP;
655 
656 	/* file component source or sink buffer */
657 	if (cd->fs.mode == FILE_WRITE) {
658 		stream = &list_first_item(&dev->bsource_list,
659 					 struct comp_buffer, sink_list)->stream;
660 	} else {
661 		stream = &list_first_item(&dev->bsink_list, struct comp_buffer,
662 					 source_list)->stream;
663 	}
664 
665 	if (stream->frame_fmt == SOF_IPC_FRAME_S16_LE)
666 		cd->sample_container_bytes = 2;
667 	else
668 		cd->sample_container_bytes = 4;
669 
670 	/* calculate period size based on config */
671 	cd->period_bytes = dev->frames * cd->sample_container_bytes *
672 		stream->channels;
673 
674 	/* file component sink/source buffer period count */
675 	switch (cd->fs.mode) {
676 	case FILE_READ:
677 		buffer = list_first_item(&dev->bsink_list, struct comp_buffer,
678 					 source_list);
679 		periods = dev->ipc_config.periods_sink;
680 		break;
681 	case FILE_WRITE:
682 		buffer = list_first_item(&dev->bsource_list,
683 					 struct comp_buffer, sink_list);
684 		periods = dev->ipc_config.periods_source;
685 		break;
686 	default:
687 		/* TODO: duplex mode */
688 		break;
689 	}
690 
691 	if (!buffer) {
692 		fprintf(stderr, "error: no sink/source buffer\n");
693 		return -EINVAL;
694 	}
695 
696 	/* set downstream buffer size */
697 	switch (dev->ipc_config.frame_fmt) {
698 	case(SOF_IPC_FRAME_S16_LE):
699 		ret = buffer_set_size(buffer, dev->frames * 2 *
700 			periods * buffer->stream.channels);
701 		if (ret < 0) {
702 			fprintf(stderr, "error: file buffer size set\n");
703 			return ret;
704 		}
705 		buffer_reset_pos(buffer, NULL);
706 
707 		/* set file function */
708 		cd->file_func = file_s16;
709 		break;
710 	case(SOF_IPC_FRAME_S24_4LE):
711 		ret = buffer_set_size(buffer, dev->frames * 4 *
712 			periods * buffer->stream.channels);
713 		if (ret < 0) {
714 			fprintf(stderr, "error: file buffer size set\n");
715 			return ret;
716 		}
717 		buffer_reset_pos(buffer, NULL);
718 
719 		/* set file function */
720 		cd->file_func = file_s24;
721 		break;
722 	case(SOF_IPC_FRAME_S32_LE):
723 		ret = buffer_set_size(buffer, dev->frames * 4 *
724 			periods * buffer->stream.channels);
725 		if (ret < 0) {
726 			fprintf(stderr, "error: file buffer size set\n");
727 			return ret;
728 		}
729 		buffer_reset_pos(buffer, NULL);
730 		break;
731 	default:
732 		return -EINVAL;
733 	}
734 
735 	dev->state = COMP_STATE_PREPARE;
736 
737 	return ret;
738 }
739 
file_reset(struct comp_dev * dev)740 static int file_reset(struct comp_dev *dev)
741 {
742 	comp_info(dev, "file_reset()");
743 	comp_set_state(dev, COMP_TRIGGER_RESET);
744 	return 0;
745 }
746 
file_get_hw_params(struct comp_dev * dev,struct sof_ipc_stream_params * params,int dir)747 static int file_get_hw_params(struct comp_dev *dev,
748 			      struct sof_ipc_stream_params *params, int dir)
749 {
750 	struct file_comp_data *cd = comp_get_drvdata(dev);
751 
752 	comp_info(dev, "file_hw_params()");
753 	params->direction = dir;
754 	params->rate = cd->rate;
755 	params->channels = cd->channels;
756 	params->buffer_fmt = 0;
757 	params->frame_fmt = cd->frame_fmt;
758 	return 0;
759 }
760 
761 static const struct comp_driver comp_file_host = {
762 	.type = SOF_COMP_HOST,
763 	.uid	= SOF_UUID(file_tr),
764 	.tctx	= &file_tr,
765 	.ops = {
766 		.create = file_new,
767 		.free = file_free,
768 		.params = file_params,
769 		.cmd = file_cmd,
770 		.trigger = file_trigger,
771 		.copy = file_copy,
772 		.prepare = file_prepare,
773 		.reset = file_reset,
774 	},
775 
776 };
777 
778 static const struct comp_driver comp_file_dai = {
779 	.type = SOF_COMP_DAI,
780 	.uid	= SOF_UUID(file_tr),
781 	.tctx	= &file_tr,
782 	.ops = {
783 		.create = file_new,
784 		.free = file_free,
785 		.params = file_params,
786 		.cmd = file_cmd,
787 		.trigger = file_trigger,
788 		.copy = file_copy,
789 		.prepare = file_prepare,
790 		.reset = file_reset,
791 		.dai_get_hw_params = file_get_hw_params,
792 	},
793 };
794 
795 static struct comp_driver_info comp_file_host_info = {
796 	.drv = &comp_file_host,
797 };
798 
799 static struct comp_driver_info comp_file_dai_info = {
800 	.drv = &comp_file_dai,
801 };
802 
sys_comp_file_init(void)803 void sys_comp_file_init(void)
804 {
805 	comp_register(&comp_file_host_info);
806 	comp_register(&comp_file_dai_info);
807 }
808