sound fixes for 7.0-rc4

There have been continuous flux but most of them are device-specific
 small fixes, while we see a few core fixes at this time (minor PCM fix
 for linked streams and a few ASoC core fixes for delayed work, etc).
 
 Core:
 - PCM: Fix use-after-free in linked stream drain
 
 * ASoC:
 - core: Fixes for delayed works, empty DMI string handling and DT overlay
 - qcom: qdsp6: Fix ADSP stop/start crash via component removal ordering
 - tegra: Add support for Tegra238 audio graph card
 - amd: Fix missing error checks for clock acquisition
 - rt1011: Fix incorrect DAPM context retrieval helper
 
 HD-audio:
 - Add quirk for Gigabyte H610M, ASUS UM6702RC, HP 14s-dr5xxx, and
   ThinkPad X390
 
 USB-audio:
 - Scarlett2: Fix NULL dereference for malformed endpoint descriptors
 - Add quirk for SPACETOUCH
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmmz4kAOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE/g7g//Z4OJ1l9eSxUjvv7pVx3nL/obn2fJOeUgIwBB
 8tNgNDXi8ctUWKpgDo0jdBIwCXu9oR+wX4A4PGp9VlIoDNbVc1vXEfV/3g3VbqDY
 P9yzwhoH9AhezXLEoSmh01YpJnkqYCiAtJARR6zN7N82Ye6/akHQHS0zMd9YRAmJ
 dV6HImxvnznzAY+ggIuPIYcdSyGp2F0iud18eiPwm/njVx2duwFxkiM9bnyXsrHw
 sRoiB3aZIF51FAwqwAy7jQ8cC0fq7YMEXqkW2smd60SJ+73N1sF1u9BzEnsyXv4b
 upbHLFDdGk62MllIkMVdwFud3Dd1hLSGR6IHD5dyi6Z9pKjLIvW0U6f44eDVBwHM
 CDVFvUKoHjETK2KNOvYvehFtbzIi0wk39LcWQtLFzunoIACPRRSP8Al4+ZcHWGNf
 cIVNoJxFBVpXRUmTfjQ6XUBlIkFthxtcAaQAnWYJ8nXL0wPYs4r/skXysxW8D5cV
 k/TLNr2rQaE0beMKGTiLJHxhTj1n4hlenVcP+xYrBOYk0f/vx0Gadabq2uy2i8p/
 aPolNRjPV9VU+5V4CfLwavoH+VeVKZHe4IKgt+wd5lP9rqN24+mpg+YFR0xcStLE
 CejZT7YUytfNZlWOUHED6+AUmyg27a+g2KDg/+KeUT5ryvGqM9sQTfw5E6+sMD1R
 pR2ww60=
 =FNK/
 -----END PGP SIGNATURE-----

Merge tag 'sound-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "There have been continuous flux but most of them are device-specific
  small fixes, while we see a few core fixes at this time (minor PCM fix
  for linked streams and a few ASoC core fixes for delayed work, etc)

  Core:
   - PCM: Fix use-after-free in linked stream drain

  ASoC:
   - core: Fixes for delayed works, empty DMI string handling and DT overlay
   - qcom: qdsp6: Fix ADSP stop/start crash via component removal ordering
   - tegra: Add support for Tegra238 audio graph card
   - amd: Fix missing error checks for clock acquisition
   - rt1011: Fix incorrect DAPM context retrieval helper

  HD-audio:
   - Add quirk for Gigabyte H610M, ASUS UM6702RC, HP 14s-dr5xxx, and
     ThinkPad X390

  USB-audio:
   - Scarlett2: Fix NULL dereference for malformed endpoint descriptors
   - Add quirk for SPACETOUCH"

* tag 'sound-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ASoC: amd: acp-mach-common: Add missing error check for clock acquisition
  ASoC: detect empty DMI strings
  ASoC: amd: acp3x-rt5682-max9836: Add missing error check for clock acquisition
  ALSA: usb-audio: Add iface reset and delay quirk for SPACETOUCH USB Audio
  ASoC: codecs: rt1011: Use component to get the dapm context in spk_mode_put
  ALSA: usb-audio: Check endpoint numbers at parsing Scarlett2 mixer interfaces
  ASoC: simple-card-utils: fix graph_util_is_ports0() for DT overlays
  ASoC: soc-core: flush delayed work before removing DAIs and widgets
  ASoC: soc-core: drop delayed_work_pending() check before flush
  ASoC: tegra: Add support for Tegra238 soundcard
  ALSA: hda/realtek: Add headset jack quirk for Thinkpad X390
  ALSA: hda/realtek: add HP Laptop 14s-dr5xxx mute LED quirk
  ALSA: hda/realtek: add quirk for ASUS UM6702RC
  ALSA: pcm: fix use-after-free on linked stream runtime in snd_pcm_drain()
  ALSA: hda/realtek: Add quirk for Gigabyte Technology to fix headphone
  firmware: cs_dsp: Fix fragmentation regression in firmware download
  ASoC: qcom: qdsp6: Fix q6apm remove ordering during ADSP stop and start
This commit is contained in:
Linus Torvalds 2026-03-13 10:15:14 -07:00
commit 56cf10db2a
15 changed files with 102 additions and 23 deletions

View File

@ -1610,11 +1610,17 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
region_name);
if (reg) {
/*
* Although we expect the underlying bus does not require
* physically-contiguous buffers, we pessimistically use
* a temporary buffer instead of trusting that the
* alignment of region->data is ok.
*/
region_len = le32_to_cpu(region->len);
if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE);
kfree(buf);
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
vfree(buf);
buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out_fw;
@ -1643,7 +1649,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
ret = 0;
out_fw:
kfree(buf);
vfree(buf);
if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@ -2331,11 +2337,17 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
}
if (reg) {
/*
* Although we expect the underlying bus does not require
* physically-contiguous buffers, we pessimistically use
* a temporary buffer instead of trusting that the
* alignment of blk->data is ok.
*/
region_len = le32_to_cpu(blk->len);
if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE);
kfree(buf);
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
vfree(buf);
buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out_fw;
@ -2366,7 +2378,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
ret = 0;
out_fw:
kfree(buf);
vfree(buf);
if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);

View File

@ -2144,6 +2144,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
for (;;) {
long tout;
struct snd_pcm_runtime *to_check;
unsigned int drain_rate;
snd_pcm_uframes_t drain_bufsz;
bool drain_no_period_wakeup;
if (signal_pending(current)) {
result = -ERESTARTSYS;
break;
@ -2163,16 +2167,25 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
snd_pcm_group_unref(group, substream);
if (!to_check)
break; /* all drained */
/*
* Cache the runtime fields needed after unlock.
* A concurrent close() on the linked stream may free
* its runtime via snd_pcm_detach_substream() once we
* release the stream lock below.
*/
drain_no_period_wakeup = to_check->no_period_wakeup;
drain_rate = to_check->rate;
drain_bufsz = to_check->buffer_size;
init_waitqueue_entry(&wait, current);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&to_check->sleep, &wait);
snd_pcm_stream_unlock_irq(substream);
if (runtime->no_period_wakeup)
if (drain_no_period_wakeup)
tout = MAX_SCHEDULE_TIMEOUT;
else {
tout = 100;
if (runtime->rate) {
long t = runtime->buffer_size * 1100 / runtime->rate;
if (drain_rate) {
long t = drain_bufsz * 1100 / drain_rate;
tout = max(t, tout);
}
tout = msecs_to_jiffies(tout);

View File

@ -6940,6 +6940,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x89da, "HP Spectre x360 14t-ea100", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a1f, "HP Laptop 14s-dr5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a26, "HP Victus 16-d1xxx (MB 8A26)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
@ -7273,6 +7274,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RCLA72", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
HDA_CODEC_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
@ -7493,6 +7495,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2288, "Thinkpad X390", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),

View File

@ -313,6 +313,7 @@ enum {
ALC897_FIXUP_HEADSET_MIC_PIN2,
ALC897_FIXUP_UNIS_H3C_X500S,
ALC897_FIXUP_HEADSET_MIC_PIN3,
ALC897_FIXUP_H610M_HP_PIN,
};
static const struct hda_fixup alc662_fixups[] = {
@ -766,6 +767,13 @@ static const struct hda_fixup alc662_fixups[] = {
{ }
},
},
[ALC897_FIXUP_H610M_HP_PIN] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x19, 0x0321403f }, /* HP out */
{ }
},
},
};
static const struct hda_quirk alc662_fixup_tbl[] = {
@ -815,6 +823,7 @@ static const struct hda_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x1458, 0xa194, "H610M H V2 DDR4", ALC897_FIXUP_H610M_HP_PIN),
SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),

View File

@ -127,8 +127,13 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != RT5682)
return -EINVAL;
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
drvdata->wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
if (IS_ERR(drvdata->wclk))
return PTR_ERR(drvdata->wclk);
drvdata->bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(drvdata->bclk))
return PTR_ERR(drvdata->bclk);
ret = snd_soc_dapm_new_controls(dapm, rt5682_widgets,
ARRAY_SIZE(rt5682_widgets));
@ -370,8 +375,13 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return -EINVAL;
if (!drvdata->soc_mclk) {
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
drvdata->wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
if (IS_ERR(drvdata->wclk))
return PTR_ERR(drvdata->wclk);
drvdata->bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(drvdata->bclk))
return PTR_ERR(drvdata->bclk);
}
ret = snd_soc_dapm_new_controls(dapm, rt5682s_widgets,

View File

@ -94,8 +94,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk");
rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
rt5682_dai_wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
if (IS_ERR(rt5682_dai_wclk))
return PTR_ERR(rt5682_dai_wclk);
rt5682_dai_bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(rt5682_dai_bclk))
return PTR_ERR(rt5682_dai_bclk);
ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
SND_JACK_HEADSET |

View File

@ -1047,7 +1047,7 @@ static int rt1011_recv_spk_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);

View File

@ -1038,11 +1038,15 @@ int graph_util_is_ports0(struct device_node *np)
else
port = np;
struct device_node *ports __free(device_node) = of_get_parent(port);
struct device_node *top __free(device_node) = of_get_parent(ports);
struct device_node *ports0 __free(device_node) = of_get_child_by_name(top, "ports");
struct device_node *ports __free(device_node) = of_get_parent(port);
const char *at = strchr(kbasename(ports->full_name), '@');
return ports0 == ports;
/*
* Since child iteration order may differ
* between a base DT and DT overlays,
* string match "ports" or "ports@0" in the node name instead.
*/
return !at || !strcmp(at, "@0");
}
EXPORT_SYMBOL_GPL(graph_util_is_ports0);

View File

@ -838,6 +838,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = {
.ack = q6apm_dai_ack,
.compress_ops = &q6apm_dai_compress_ops,
.use_dai_pcm_id = true,
.remove_order = SND_SOC_COMP_ORDER_EARLY,
};
static int q6apm_dai_probe(struct platform_device *pdev)

View File

@ -278,6 +278,7 @@ static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
.of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name,
.be_pcm_base = AUDIOREACH_BE_PCM_BASE,
.use_dai_pcm_id = true,
.remove_order = SND_SOC_COMP_ORDER_FIRST,
};
static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev)

View File

@ -715,6 +715,7 @@ static const struct snd_soc_component_driver q6apm_audio_component = {
.name = APM_AUDIO_DRV_NAME,
.probe = q6apm_audio_probe,
.remove = q6apm_audio_remove,
.remove_order = SND_SOC_COMP_ORDER_LAST,
};
static int apm_probe(gpr_device_t *gdev)

View File

@ -462,8 +462,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
list_del(&rtd->list);
if (delayed_work_pending(&rtd->delayed_work))
flush_delayed_work(&rtd->delayed_work);
flush_delayed_work(&rtd->delayed_work);
snd_soc_pcm_component_free(rtd);
/*
@ -1864,12 +1863,15 @@ static void cleanup_dmi_name(char *name)
/*
* Check if a DMI field is valid, i.e. not containing any string
* in the black list.
* in the black list and not the empty string.
*/
static int is_dmi_valid(const char *field)
{
int i = 0;
if (!field[0])
return 0;
while (dmi_blacklist[i]) {
if (strstr(field, dmi_blacklist[i]))
return 0;
@ -2122,6 +2124,9 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
for_each_card_rtds(card, rtd)
if (rtd->initialized)
snd_soc_link_exit(rtd);
/* flush delayed work before removing DAIs and DAPM widgets */
snd_soc_flush_all_delayed_work(card);
/* remove and free each DAI */
soc_remove_link_dais(card);
soc_remove_link_components(card);

View File

@ -231,6 +231,15 @@ static const struct tegra_audio_cdata tegra186_data = {
.plla_out0_rates[x11_RATE] = 45158400,
};
static const struct tegra_audio_cdata tegra238_data = {
/* PLLA */
.plla_rates[x8_RATE] = 1277952000,
.plla_rates[x11_RATE] = 1264435200,
/* PLLA_OUT0 */
.plla_out0_rates[x8_RATE] = 49152000,
.plla_out0_rates[x11_RATE] = 45158400,
};
static const struct tegra_audio_cdata tegra264_data = {
/* PLLA1 */
.plla_rates[x8_RATE] = 983040000,
@ -245,6 +254,8 @@ static const struct of_device_id graph_of_tegra_match[] = {
.data = &tegra210_data },
{ .compatible = "nvidia,tegra186-audio-graph-card",
.data = &tegra186_data },
{ .compatible = "nvidia,tegra238-audio-graph-card",
.data = &tegra238_data },
{ .compatible = "nvidia,tegra264-audio-graph-card",
.data = &tegra264_data },
{},

View File

@ -8251,6 +8251,8 @@ static int scarlett2_find_fc_interface(struct usb_device *dev,
if (desc->bInterfaceClass != 255)
continue;
if (desc->bNumEndpoints < 1)
continue;
epd = get_endpoint(intf->altsetting, 0);
private->bInterfaceNumber = desc->bInterfaceNumber;

View File

@ -2243,6 +2243,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_IFACE_DELAY | QUIRK_FLAG_FORCE_IFACE_RESET),
DEVICE_FLG(0x0661, 0x0883, /* iBasso DC04 Ultra */
QUIRK_FLAG_DSD_RAW),
DEVICE_FLG(0x0666, 0x0880, /* SPACETOUCH USB Audio */
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */