From 81ac3fa5962271fe581c7e7dddcedc00bd0a085a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 15 Jan 2026 13:19:39 -0800 Subject: [PATCH 1/3] ASoC: SOF: Intel: hda: Fix NULL pointer dereference If there's a mismatch between the DAI links in the machine driver and the topology, it is possible that the playback/capture widget is not set, especially in the case of loopback capture for echo reference where we use the dummy DAI link. Return the error when the widget is not set to avoid a null pointer dereference like below when the topology is broken. RIP: 0010:hda_dai_get_ops.isra.0+0x14/0xa0 [snd_sof_intel_hda_common] Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 883d0d3bae9ec2..3c742d53513337 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -70,12 +70,22 @@ static const struct hda_dai_widget_dma_ops * hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); - struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_widget *swidget; struct snd_sof_dev *sdev; struct snd_sof_dai *sdai; - sdev = widget_to_sdev(w); + /* + * this is unlikely if the topology and the machine driver DAI links match. + * But if there's a missing DAI link in topology, this will prevent a NULL pointer + * dereference later on. + */ + if (!w) { + dev_err(cpu_dai->dev, "%s: widget is NULL\n", __func__); + return NULL; + } + sdev = widget_to_sdev(w); + swidget = w->dobj.private; if (!swidget) { dev_err(sdev->dev, "%s: swidget is NULL\n", __func__); return NULL; From d2671f1fcbdbf90e81b8a1c92c98a62a95f48a20 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 16 Jan 2026 14:04:51 -0800 Subject: [PATCH 2/3] ASoC: SOF: Intel: hda: Add a virtual CPU DAI Add a virtual CPU DAI for loopback capture for echo reference implementation. We can't use the snd-soc-dummy-dai because it is already used for the bluetooth DAI link. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 8 ++++++++ sound/soc/sof/intel/hda.h | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 3c742d53513337..15faedeec16d78 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -866,6 +866,14 @@ struct snd_soc_dai_driver skl_dai[] = { .channels_max = 4, }, }, +{ + /* Virtual CPU DAI for Echo reference */ + .name = "Loopback Virtual Pin", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) { .name = "iDisp1 Pin", diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3fe00c269114ad..3f0966477ace21 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -418,10 +418,10 @@ (HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl)) /* Number of DAIs */ -#define SOF_SKL_NUM_DAIS_NOCODEC 8 +#define SOF_SKL_NUM_DAIS_NOCODEC 9 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) -#define SOF_SKL_NUM_DAIS 15 +#define SOF_SKL_NUM_DAIS 16 #else #define SOF_SKL_NUM_DAIS SOF_SKL_NUM_DAIS_NOCODEC #endif From b1a743e70867551717372f76ce35fc767971b4db Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 16 Jan 2026 14:06:37 -0800 Subject: [PATCH 3/3] fixup! ASoC: Intel: sof_sdw: Add a DAI link for loopback capture Don't use the dummy CPU DAI but use the virtual loopback capture CPU DAI instead. Signed-off-by: Ranjani Sridharan --- sound/soc/intel/boards/sof_sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 2c8effd052b94b..578d72819fca7c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1219,7 +1219,7 @@ static int create_echoref_dailink(struct snd_soc_card *card, * fe <-> be connection for loopback capture for echo reference */ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, - 0, 1, "snd-soc-dummy-dai", "dummy", + 0, 1, "Loopback Virtual Pin", "dummy", snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, 1, NULL, NULL); if (ret)