// 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) 2018 Intel Corporation // // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // // PCM Layer, interface between ALSA and IPC. //
/* *Handlerepeatedcallstohw_params()withoutfree_pcm()in *between.AtleastALSAOSSemulationdependsonthis.
*/ 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;
}
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); if (ret < 0) return ret;
}
/* create compressed page table for audio firmware */ if (runtime->buffer_changed) { struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
ret = snd_sof_create_page_table(component->dev, dmab,
spcm->stream[substream->stream].page_table.area,
runtime->dma_bytes); if (ret < 0) return ret;
}
if (pcm_ops && pcm_ops->hw_params) {
ret = pcm_ops->hw_params(component, substream, params, &platform_params); if (ret < 0) return ret;
}
spcm->prepared[substream->stream] = true;
/* save pcm hw_params */
memcpy(&spcm->params[substream->stream], params, sizeof(*params));
return0;
}
staticint sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
{ conststruct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); int ret; int err = 0;
if (spcm->prepared[substream->stream]) { /* stop DMA first if needed */ if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream,
SNDRV_PCM_TRIGGER_STOP);
/* free PCM in the DSP */ if (pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(sdev->component, substream); if (ret < 0) {
spcm_err(spcm, substream->stream, "pcm_ops->hw_free failed %d\n", ret);
err = ret;
}
}
if (spcm->prepared[substream->stream]) { if (!spcm->pending_stop[substream->stream]) return0;
/* *thiscaseshouldbereachedincaseofxrunswhereweabsolutely *wanttofree-upandresetallPCM/DMAresources
*/
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); if (ret < 0) return ret;
}
/* set hw_params */
ret = sof_pcm_hw_params(component,
substream, &spcm->params[substream->stream]); if (ret < 0) {
spcm_err(spcm, substream->stream, "failed to set hw_params after resume\n"); return ret;
}
if (!ipc_first)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
if (pcm_ops && pcm_ops->trigger)
ret = pcm_ops->trigger(component, substream, cmd);
switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_START: /* invoke platform trigger to start DMA only if pcm_ops is successful */ if (ipc_first && !ret)
snd_sof_pcm_platform_trigger(sdev, substream, cmd); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */ if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* free PCM if reset_hw_params is set and the STOP IPC is successful */ if (!ret && reset_hw_params)
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, false);
/* nothing to do for BE */ if (rtd->dai_link->no_pcm) return0;
if (pcm_ops && pcm_ops->pointer)
ret = pcm_ops->pointer(component, substream, &host);
if (ret != -EOPNOTSUPP) return ret ? ret : host;
/* use dsp ops pointer callback directly if set */ if (sof_ops(sdev)->pcm_pointer) return sof_ops(sdev)->pcm_pointer(sdev, substream);
spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL;
/* read position from DSP */
host = bytes_to_frames(substream->runtime,
spcm->stream[substream->stream].posn.host_posn);
dai = bytes_to_frames(substream->runtime,
spcm->stream[substream->stream].posn.dai_posn);
/* find SOF PCM for this RTD */
spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) {
dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n",
rtd->dai_link->id); return0;
}
/* fixup the BE DAI link to match any values from topology */ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
{ struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai =
snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); conststruct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
/* no topology exists for this BE, try a common configuration */ if (!dai) {
dev_warn(component->dev, "warning: no topology found for BE DAI %s config\n",
rtd->dai_link->name);
/* set 48k, stereo, 16bits by default */
rate->min = 48000;
rate->max = 48000;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.