sound/soc/sof/ipc4-pcm.c

Source file repositories/reference/linux-study-clean/sound/soc/sof/ipc4-pcm.c

File Facts

System
Linux kernel
Corpus path
sound/soc/sof/ipc4-pcm.c
Extension
.c
Size
40962 bytes
Lines
1323
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sof_ipc4_timestamp_info {
	struct sof_ipc4_copier *host_copier;
	struct sof_ipc4_copier *dai_copier;
	u64 stream_start_offset;
	u64 stream_end_offset;
	u32 llp_offset;

	snd_pcm_sframes_t delay;
};

/**
 * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data
 * @time_info: pointer to time info struct if it is supported, otherwise NULL
 * @chain_dma_allocated: indicates the ChainDMA allocation state
 */
struct sof_ipc4_pcm_stream_priv {
	struct sof_ipc4_timestamp_info *time_info;

	bool chain_dma_allocated;
};

/*
 * Modulus to use to compare host and link position counters. The sampling
 * rates may be different, so the raw hardware counters will wrap
 * around at different times. To calculate differences, use
 * DELAY_BOUNDARY as a common modulus. This value must be smaller than
 * the wrap-around point of any hardware counter, and larger than any
 * valid delay measurement.
 */
#define DELAY_BOUNDARY		U32_MAX

#define DELAY_MAX		(DELAY_BOUNDARY >> 1)

static inline struct sof_ipc4_timestamp_info *
sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
{
	struct sof_ipc4_pcm_stream_priv *stream_priv = sps->private;

	return stream_priv->time_info;
}

static
char *sof_ipc4_set_multi_pipeline_state_debug(struct snd_sof_dev *sdev, char *buf, size_t size,
					      struct ipc4_pipeline_set_state_data *trigger_list)
{
	int i, offset = 0;

	for (i = 0; i < trigger_list->count; i++) {
		offset += snprintf(buf + offset, size - offset, " %d",
				   trigger_list->pipeline_instance_ids[i]);

		if (offset >= size - 1) {
			buf[size - 1] = '\0';
			break;
		}
	}
	return buf;
}

static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state,
					     struct ipc4_pipeline_set_state_data *trigger_list)
{
	struct sof_ipc4_msg msg = {{ 0 }};
	u32 primary, ipc_size;
	char debug_buf[32];

	/* trigger a single pipeline */
	if (trigger_list->count == 1)
		return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
						   state);

	dev_dbg(sdev->dev, "Set pipelines %s to state %d%s",
		sof_ipc4_set_multi_pipeline_state_debug(sdev, debug_buf, sizeof(debug_buf),
							trigger_list),
		state, sof_ipc4_pipeline_state_str(state));

	primary = state;
	primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
	primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
	primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
	msg.primary = primary;

	/* trigger multiple pipelines with a single IPC */
	msg.extension = SOF_IPC4_GLB_PIPE_STATE_EXT_MULTI;

	/* ipc_size includes the count and the pipeline IDs for the number of pipelines */
	ipc_size = sizeof(u32) * (trigger_list->count + 1);
	msg.data_size = ipc_size;
	msg.data_ptr = trigger_list;

Annotation

Implementation Notes