sound/soc/sof/pcm.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/sof/pcm.c
Extension
.c
Size
24957 bytes
Lines
871
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

if (ret < 0) {
			spcm_err(spcm, dir, "dai %s has no valid %s path\n",
				 dai->name, snd_pcm_direction_name(dir));
			return ret;
		}

		spcm->stream[dir].list = list;

		ret = sof_widget_list_prepare(sdev, spcm, params, platform_params, dir);
		if (ret < 0) {
			spcm_err(spcm, dir, "widget list prepare failed\n");
			spcm->stream[dir].list = NULL;
			snd_soc_dapm_dai_free_widgets(&list);
			return ret;
		}
	}

	return 0;
}

static struct snd_sof_widget *snd_sof_find_swidget_by_comp_id(struct snd_sof_dev *sdev,
							      int comp_id)
{
	struct snd_sof_widget *swidget;

	list_for_each_entry(swidget, &sdev->widget_list, list) {
		if (comp_id == swidget->comp_id)
			return swidget;
	}

	return NULL;
}

static int sof_pcm_hw_params(struct snd_soc_component *component,
			     struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params)
{
	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
	const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
	struct snd_sof_platform_stream_params *platform_params;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_sof_widget *host_widget;
	struct snd_sof_pcm *spcm;
	int ret;

	/* nothing to do for BE */
	if (rtd->dai_link->no_pcm)
		return 0;

	spcm = snd_sof_find_spcm_dai(component, rtd);
	if (!spcm)
		return -EINVAL;

	spcm_dbg(spcm, substream->stream, "Entry: hw_params\n");

	if (!sdev->dspless_mode_selected) {
		/*
		 * Make sure that the DSP is booted up, which might not be the
		 * case if the on-demand DSP boot is used
		 */
		ret = snd_sof_boot_dsp_firmware(sdev);
		if (ret)
			return ret;
	}

	/*
	 * Handle repeated calls to hw_params() without free_pcm() in
	 * between. At least ALSA OSS emulation depends on this.
	 */
	if (spcm->prepared[substream->stream] && pcm_ops && pcm_ops->hw_free) {
		ret = pcm_ops->hw_free(component, substream);
		if (ret < 0)
			return ret;

		spcm->prepared[substream->stream] = false;
	}

	platform_params = &spcm->platform_params[substream->stream];
	ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, platform_params);
	if (ret < 0) {
		spcm_err(spcm, substream->stream, "platform hw params failed\n");
		return ret;
	}

	/* if this is a repeated hw_params without hw_free, skip setting up widgets */
	if (!spcm->stream[substream->stream].list) {
		ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, params, platform_params,
						      substream->stream);

Annotation

Implementation Notes