128 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
 | |
| //
 | |
| // This file is provided under a dual BSD/GPLv2 license.  When using or
 | |
| // redistributing this file, you may do so under either license.
 | |
| //
 | |
| // Copyright(c) 2019 Intel Corporation
 | |
| //
 | |
| // Authors: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
 | |
| 
 | |
| /* Generic SOF IPC code */
 | |
| 
 | |
| #include <linux/device.h>
 | |
| #include <linux/export.h>
 | |
| #include <linux/module.h>
 | |
| #include <linux/types.h>
 | |
| 
 | |
| #include <sound/pcm.h>
 | |
| #include <sound/sof/stream.h>
 | |
| 
 | |
| #include "ops.h"
 | |
| #include "sof-priv.h"
 | |
| #include "sof-audio.h"
 | |
| 
 | |
| struct sof_stream {
 | |
| 	size_t posn_offset;
 | |
| };
 | |
| 
 | |
| /* Mailbox-based Generic IPC implementation */
 | |
| int sof_ipc_msg_data(struct snd_sof_dev *sdev,
 | |
| 		     struct snd_sof_pcm_stream *sps,
 | |
| 		     void *p, size_t sz)
 | |
| {
 | |
| 	if (!sps || !sdev->stream_box.size) {
 | |
| 		snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
 | |
| 	} else {
 | |
| 		size_t posn_offset;
 | |
| 
 | |
| 		if (sps->substream) {
 | |
| 			struct sof_stream *stream = sps->substream->runtime->private_data;
 | |
| 
 | |
| 			/* The stream might already be closed */
 | |
| 			if (!stream)
 | |
| 				return -ESTRPIPE;
 | |
| 
 | |
| 			posn_offset = stream->posn_offset;
 | |
| 		} else {
 | |
| 
 | |
| 			struct sof_compr_stream *sstream = sps->cstream->runtime->private_data;
 | |
| 
 | |
| 			if (!sstream)
 | |
| 				return -ESTRPIPE;
 | |
| 
 | |
| 			posn_offset = sstream->posn_offset;
 | |
| 		}
 | |
| 
 | |
| 		snd_sof_dsp_mailbox_read(sdev, posn_offset, p, sz);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| EXPORT_SYMBOL(sof_ipc_msg_data);
 | |
| 
 | |
| int sof_set_stream_data_offset(struct snd_sof_dev *sdev,
 | |
| 			       struct snd_sof_pcm_stream *sps,
 | |
| 			       size_t posn_offset)
 | |
| {
 | |
| 	/* check if offset is overflow or it is not aligned */
 | |
| 	if (posn_offset > sdev->stream_box.size ||
 | |
| 	    posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	posn_offset += sdev->stream_box.offset;
 | |
| 
 | |
| 	if (sps->substream) {
 | |
| 		struct sof_stream *stream = sps->substream->runtime->private_data;
 | |
| 
 | |
| 		stream->posn_offset = posn_offset;
 | |
| 		dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
 | |
| 			sps->substream->stream, posn_offset);
 | |
| 	} else if (sps->cstream) {
 | |
| 		struct sof_compr_stream *sstream = sps->cstream->runtime->private_data;
 | |
| 
 | |
| 		sstream->posn_offset = posn_offset;
 | |
| 		dev_dbg(sdev->dev, "compr: stream dir %d, posn mailbox offset is %zu",
 | |
| 			sps->cstream->direction, posn_offset);
 | |
| 	} else {
 | |
| 		dev_err(sdev->dev, "No stream opened");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| EXPORT_SYMBOL(sof_set_stream_data_offset);
 | |
| 
 | |
| int sof_stream_pcm_open(struct snd_sof_dev *sdev,
 | |
| 			struct snd_pcm_substream *substream)
 | |
| {
 | |
| 	struct sof_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
 | |
| 
 | |
| 	if (!stream)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	/* binding pcm substream to hda stream */
 | |
| 	substream->runtime->private_data = stream;
 | |
| 
 | |
| 	/* align to DMA minimum transfer size */
 | |
| 	snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
 | |
| 
 | |
| 	/* avoid circular buffer wrap in middle of period */
 | |
| 	snd_pcm_hw_constraint_integer(substream->runtime,
 | |
| 				      SNDRV_PCM_HW_PARAM_PERIODS);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| EXPORT_SYMBOL(sof_stream_pcm_open);
 | |
| 
 | |
| int sof_stream_pcm_close(struct snd_sof_dev *sdev,
 | |
| 			 struct snd_pcm_substream *substream)
 | |
| {
 | |
| 	struct sof_stream *stream = substream->runtime->private_data;
 | |
| 
 | |
| 	substream->runtime->private_data = NULL;
 | |
| 	kfree(stream);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| EXPORT_SYMBOL(sof_stream_pcm_close);
 |