aboutsummaryrefslogtreecommitdiffstats
diff options
authorThierry Reding <treding@nvidia.com>2026-04-30 09:31:28 +0200
committerThierry Reding <treding@nvidia.com>2026-04-30 09:31:28 +0200
commitd87dbdefa6d2160a29b734cfb69de75ddcb46c25 (patch)
treec8f5915ec14dd4dfeae7985e2bc90db5b551967c
parent0cb0f612490e40d60cbdb3c05ba462ca292e86f7 (diff)
parente052a1f7199260eda4d6ca08a59c3b98738f8491 (diff)
downloadlinux-next-d87dbdefa6d2160a29b734cfb69de75ddcb46c25.tar.gz
Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
-rw-r--r--sound/core/oss/pcm_oss.c29
-rw-r--r--sound/drivers/aloop.c43
-rw-r--r--sound/hda/codecs/Makefile2
-rw-r--r--sound/hda/codecs/conexant.c8
-rw-r--r--sound/hda/codecs/realtek/alc269.c14
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.c31
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.h1
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_spi.c14
-rw-r--r--sound/hda/core/hdmi_chmap.c11
-rw-r--r--sound/soc/amd/acp/acp-legacy-mach.c2
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c22
-rw-r--r--sound/soc/amd/acp/acp-mach.h4
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c2
-rw-r--r--sound/soc/codecs/ab8500-codec.c6
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c9
-rw-r--r--sound/soc/codecs/cs35l56-shared.c7
-rw-r--r--sound/soc/codecs/es8389.c2
-rw-r--r--sound/soc/codecs/tas2764.c1
-rw-r--r--sound/soc/codecs/tas2770.c4
-rw-r--r--sound/soc/codecs/wcd937x.c26
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c1
-rw-r--r--sound/soc/sof/intel/hda.c3
-rw-r--r--sound/soc/spacemit/k1_i2s.c49
-rw-r--r--sound/soc/tegra/Makefile1
-rw-r--r--sound/usb/caiaq/device.c6
-rw-r--r--sound/usb/caiaq/input.c2
-rw-r--r--sound/usb/misc/ua101.c7
-rw-r--r--sound/usb/mixer.c10
-rw-r--r--sound/usb/quirks-table.h4
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--sound/usb/stream.c62
-rw-r--r--sound/usb/stream.h3
32 files changed, 266 insertions, 122 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index a140a0d9abb80..33fd34f0d615d 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2155,10 +2155,16 @@ static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file)
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger)
- result |= PCM_ENABLE_OUTPUT;
- if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger)
- result |= PCM_ENABLE_INPUT;
+ if (psubstream && psubstream->runtime) {
+ guard(mutex)(&psubstream->runtime->oss.params_lock);
+ if (psubstream->runtime->oss.trigger)
+ result |= PCM_ENABLE_OUTPUT;
+ }
+ if (csubstream && csubstream->runtime) {
+ guard(mutex)(&csubstream->runtime->oss.params_lock);
+ if (csubstream->runtime->oss.trigger)
+ result |= PCM_ENABLE_INPUT;
+ }
return result;
}
@@ -2832,6 +2838,17 @@ static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
runtime->oss.period_frames;
}
+static bool need_input_retrigger(struct snd_pcm_runtime *runtime)
+{
+ bool ret;
+
+ guard(mutex)(&runtime->oss.params_lock);
+ ret = runtime->oss.trigger;
+ if (ret)
+ runtime->oss.trigger = 0;
+ return ret;
+}
+
static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
{
struct snd_pcm_oss_file *pcm_oss_file;
@@ -2864,11 +2881,11 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM;
}
- if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
+ if (ostate != SNDRV_PCM_STATE_RUNNING &&
+ need_input_retrigger(runtime)) {
struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile));
ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- runtime->oss.trigger = 0;
snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
}
}
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index aa0d2fcb1a180..a37a1695f51c7 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -99,6 +99,9 @@ struct loopback_ops {
struct loopback_cable {
spinlock_t lock;
struct loopback_pcm *streams[2];
+ /* in-flight peer stops running outside cable->lock */
+ atomic_t stop_count;
+ wait_queue_head_t stop_wait;
struct snd_pcm_hardware hw;
/* flags */
unsigned int valid;
@@ -366,8 +369,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE)
return -EIO;
- else if (cruntime->state == SNDRV_PCM_STATE_RUNNING)
+ else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) {
+ /* close must not free the peer runtime below */
+ atomic_inc(&cable->stop_count);
stop_capture = true;
+ }
}
setup = get_setup(dpcm_play);
@@ -396,8 +402,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
}
}
- if (stop_capture)
+ if (stop_capture) {
snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
+ if (atomic_dec_and_test(&cable->stop_count))
+ wake_up(&cable->stop_wait);
+ }
return 0;
}
@@ -1049,23 +1058,29 @@ static void free_cable(struct snd_pcm_substream *substream)
struct loopback *loopback = substream->private_data;
int dev = get_cable_index(substream);
struct loopback_cable *cable;
+ struct loopback_pcm *dpcm;
+ bool other_alive;
cable = loopback->cables[substream->number][dev];
if (!cable)
return;
- if (cable->streams[!substream->stream]) {
- /* other stream is still alive */
- guard(spinlock_irq)(&cable->lock);
- cable->streams[substream->stream] = NULL;
- } else {
- struct loopback_pcm *dpcm = substream->runtime->private_data;
- if (cable->ops && cable->ops->close_cable && dpcm)
- cable->ops->close_cable(dpcm);
- /* free the cable */
- loopback->cables[substream->number][dev] = NULL;
- kfree(cable);
+ scoped_guard(spinlock_irq, &cable->lock) {
+ cable->streams[substream->stream] = NULL;
+ other_alive = cable->streams[!substream->stream];
}
+
+ /* Pair with the stop_count increment in loopback_check_format(). */
+ wait_event(cable->stop_wait, !atomic_read(&cable->stop_count));
+ if (other_alive)
+ return;
+
+ dpcm = substream->runtime->private_data;
+ if (cable->ops && cable->ops->close_cable && dpcm)
+ cable->ops->close_cable(dpcm);
+ /* free the cable */
+ loopback->cables[substream->number][dev] = NULL;
+ kfree(cable);
}
static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
@@ -1260,6 +1275,8 @@ static int loopback_open(struct snd_pcm_substream *substream)
goto unlock;
}
spin_lock_init(&cable->lock);
+ atomic_set(&cable->stop_count, 0);
+ init_waitqueue_head(&cable->stop_wait);
cable->hw = loopback_pcm_hardware;
if (loopback->timer_source)
cable->ops = &loopback_snd_timer_ops;
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
index e7f03e281999f..88d2f8a79467b 100644
--- a/sound/hda/codecs/Makefile
+++ b/sound/hda/codecs/Makefile
@@ -7,7 +7,6 @@ snd-hda-codec-cm9825-y := cm9825.o
snd-hda-codec-analog-y := analog.o
snd-hda-codec-ca0110-y := ca0110.o
snd-hda-codec-ca0132-y := ca0132.o
-snd-hda-codec-cmedia-y := cmedia.o
snd-hda-codec-conexant-y := conexant.o
snd-hda-codec-idt-y := sigmatel.o
snd-hda-codec-senarytech-y := senarytech.o
@@ -26,7 +25,6 @@ obj-$(CONFIG_SND_HDA_CODEC_CM9825) += snd-hda-codec-cm9825.o
obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
-obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
index 3a9717df39b4b..e3b6aaabe3a9c 100644
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -1175,6 +1175,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)
static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
struct conexant_spec *spec;
+ struct hda_jack_callback *callback;
int err;
codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
@@ -1190,7 +1191,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
case 0x14f11f86:
case 0x14f11f87:
spec->is_cx11880_sn6140 = true;
- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
+ callback = snd_hda_jack_detect_enable_callback(codec, 0x19,
+ cx_update_headset_mic_vref);
+ if (IS_ERR(callback)) {
+ err = PTR_ERR(callback);
+ goto error;
+ }
break;
}
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index d720565db4aaf..a9cd03bb73c41 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -3694,6 +3694,17 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
spec->power_hook = alc287_s4_power_gpio3_default;
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
}
+
+static void alc287_fixup_tb_vmaster_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->gen.vmaster_mute_led = 1;
+
+ alc287_fixup_bind_dacs(codec, fix, action);
+}
/* GPIO2: mute led GPIO3: micmute led */
static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -6448,7 +6459,7 @@ static const struct hda_fixup alc269_fixups[] = {
},
[ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
.type = HDA_FIXUP_FUNC,
- .v.func = alc287_fixup_bind_dacs,
+ .v.func = alc287_fixup_tb_vmaster_led,
.chained = true,
.chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
},
@@ -6717,6 +6728,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
index 1ace4beef5085..4c8d01799931c 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -180,11 +180,15 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
{
struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
unsigned int reg_val;
- int i;
+ int i, ret;
cs35l56_hda_wait_dsp_ready(cs35l56);
- regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
+ ret = regmap_read(cs35l56->base.regmap, kcontrol->private_value,
+ &reg_val);
+ if (ret)
+ return ret;
+
reg_val &= CS35L56_ASP_TXn_SRC_MASK;
for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
@@ -203,15 +207,20 @@ static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
unsigned int item = ucontrol->value.enumerated.item[0];
bool changed;
+ int ret;
if (item >= CS35L56_NUM_INPUT_SRC)
return -EINVAL;
cs35l56_hda_wait_dsp_ready(cs35l56);
- regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
- CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
- &changed);
+ ret = regmap_update_bits_check(cs35l56->base.regmap,
+ kcontrol->private_value,
+ CS35L56_INPUT_MASK,
+ cs35l56_tx_input_values[item],
+ &changed);
+ if (ret)
+ return ret;
return changed;
}
@@ -967,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev)
static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)
{
/* The cirrus,dev-index property has the wrong values */
+ cs35l56->num_amps = 2;
switch (*bus_addr) {
case 0x30:
cs35l56->index = 1;
@@ -1016,7 +1026,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
char hid_string[8];
struct acpi_device *adev;
const char *property, *sub;
- size_t nval;
int i, ret;
/*
@@ -1052,13 +1061,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
ret = -EINVAL;
goto err;
}
- nval = ret;
+ cs35l56->num_amps = ret;
- ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
+ ret = device_property_read_u32_array(cs35l56->base.dev, property, values,
+ cs35l56->num_amps);
if (ret)
goto err;
- for (i = 0; i < nval; i++) {
+ for (i = 0; i < cs35l56->num_amps; i++) {
if (values[i] == id) {
cs35l56->index = i;
break;
@@ -1081,7 +1091,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
"Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
PTR_ERR(sub));
} else {
- ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
+ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index,
+ cs35l56->num_amps, -1);
if (ret == -ENOENT) {
cs35l56->system_name = sub;
} else if (ret >= 0) {
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h
index cb4b5e7356a35..3705af7c186b3 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.h
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.h
@@ -26,6 +26,7 @@ struct cs35l56_hda {
struct work_struct dsp_work;
int index;
+ int num_amps;
const char *system_name;
const char *amp_name;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index 560f2385212dd..0e4f3553f2738 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -132,10 +132,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
int ret, val;
/*
- * In our TAS2781 SPI mode, read/write was masked in last bit of
- * address, it cause regmap_update_bits() not work as expected.
+ * In TAS2781 SPI mode, when accessing non-book-zero or page numbers
+ * greater than 1 in book 0, an additional byte must be read. The
+ * first byte in such cases is a dummy byte and should be ignored.
*/
- ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+ unsigned char buf[2];
+
+ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2);
+ val = buf[1];
+ } else {
+ ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+ }
if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
return ret;
diff --git a/sound/hda/core/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c
index 7b276047f85a7..c897fc443467c 100644
--- a/sound/hda/core/hdmi_chmap.c
+++ b/sound/hda/core/hdmi_chmap.c
@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap,
if (hdmi_channel_mapping[ca][1] == 0) {
int hdmi_slot = 0;
/* fill actual channel mappings in ALSA channel (i) order */
- for (i = 0; i < ch_alloc->channels; i++) {
- while (!WARN_ON(hdmi_slot >= 8) &&
- !ch_alloc->speakers[7 - hdmi_slot])
- hdmi_slot++; /* skip zero slots */
+ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) {
+ while (!ch_alloc->speakers[7 - hdmi_slot]) {
+ /* skip zero slots */
+ if (++hdmi_slot >= 8)
+ goto out;
+ }
hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++;
}
+ out:
/* fill the rest of the slots with ALSA channel 0xf */
for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++)
if (!ch_alloc->speakers[7 - hdmi_slot])
diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index a7a551366a409..235d6cc83fa98 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev)
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
dmi_id = dmi_first_match(acp_quirk_table);
- if (dmi_id && dmi_id->driver_data)
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
ret = acp_legacy_dai_links_create(card);
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 09f6c9a2c0410..ef784cca13f2b 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -20,6 +20,7 @@
#include <sound/soc.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include "../../codecs/rt5682.h"
#include "../../codecs/rt1019.h"
@@ -37,15 +38,21 @@
#define NAU8821_FREQ_OUT 12288000
#define MAX98388_CODEC_DAI "max98388-aif1"
-#define TDM_MODE_ENABLE 1
-
const struct dmi_system_id acp_quirk_table[] = {
{
/* Google skyrim proto-0 */
.matches = {
DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"),
},
- .driver_data = (void *)TDM_MODE_ENABLE,
+ .driver_data = (void *)QUIRK_TDM_MODE_ENABLE,
+ },
+ {
+ /* Valve Steam Deck OLED */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ .driver_data = (void *)QUIRK_REMAP_DMIC_BT,
},
{}
};
@@ -1401,6 +1408,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
struct snd_soc_dai_link *links;
struct device *dev = card->dev;
struct acp_card_drvdata *drv_data = card->drvdata;
+ const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table);
int i = 0, num_links = 0;
if (drv_data->hs_cpu_id)
@@ -1572,6 +1580,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
+
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT)
+ links[i].id = DMIC_BE_ID;
i++;
}
@@ -1587,6 +1598,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].capture_only = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
+
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) {
+ links[i].id = BT_BE_ID;
+ dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n");
+ }
}
card->dai_link = links;
diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h
index f94c30c20f20b..7177d3fd96192 100644
--- a/sound/soc/amd/acp/acp-mach.h
+++ b/sound/soc/amd/acp/acp-mach.h
@@ -26,6 +26,10 @@
#define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata)
+/* List of DMI quirks - check acp-mach-common.c for usage. */
+#define QUIRK_TDM_MODE_ENABLE 1
+#define QUIRK_REMAP_DMIC_BT 2
+
enum be_id {
HEADSET_BE_ID = 0,
AMP_BE_ID,
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 6215e31eceddf..36ecef7013b9c 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev)
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
- if (dmi_id && dmi_id->driver_data)
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index fdda1b747bf7e..8ab2e60f80b4f 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component)
return status;
}
fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
+ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
drvdata->anc_fir_values = (long *)fc->value;
fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
+ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
drvdata->anc_iir_values = (long *)fc->value;
fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
+ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
drvdata->sid_fir_values = (long *)fc->value;
snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index 3602b5b9f7d77..dd09bac652f7f 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -456,8 +456,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395)
usleep_range(AW88395_1000_US, AW88395_1000_US + 10);
gpiod_set_value_cansleep(aw88395->reset_gpio, 1);
usleep_range(AW88395_1000_US, AW88395_1000_US + 10);
- } else {
- dev_err(aw88395->aw_pa->dev, "%s failed", __func__);
}
}
@@ -522,9 +520,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, aw88395);
aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(aw88395->reset_gpio))
- dev_info(&i2c->dev, "reset gpio not defined\n");
-
+ if (IS_ERR(aw88395->reset_gpio)) {
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio),
+ "failed to get reset gpio\n");
+ }
/* hardware reset */
aw88395_hw_reset(aw88395);
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index e05d975ba7945..033e56d5e9db4 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED");
static const struct reg_default cs35l56_reg_defaults[] = {
- /* no defaults for OTP_MEM - first read populates cache */
-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -138,8 +136,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
};
static const struct reg_default cs35l63_reg_defaults[] = {
- /* no defaults for OTP_MEM - first read populates cache */
-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg)
case CS35L56_GLOBAL_ENABLES: /* owned by firmware */
case CS35L56_BLOCK_ENABLES: /* owned by firmware */
case CS35L56_BLOCK_ENABLES2: /* owned by firmware */
+ case CS35L56_OTP_MEM_53:
+ case CS35L56_OTP_MEM_54:
+ case CS35L56_OTP_MEM_55:
case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG:
case CS35L56_UPDATE_REGS:
case CS35L56_REFCLK_INPUT: /* owned by firmware */
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 8d418cae371a8..449d9574b03a8 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -892,7 +892,7 @@ static int es8389_probe(struct snd_soc_component *component)
return ret;
}
- es8389->mclk = devm_clk_get(component->dev, "mclk");
+ es8389->mclk = devm_clk_get_optional(component->dev, "mclk");
if (IS_ERR(es8389->mclk))
return dev_err_probe(component->dev, PTR_ERR(es8389->mclk),
"ES8389 is unable to get mclk\n");
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 423b7073b3022..6aab6d2b74191 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -904,6 +904,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case TAS2764_SW_RST:
+ case TAS2764_TEMP:
case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
case TAS2764_INT_CLK_CFG:
return true;
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index d4d7d056141bd..50501bcbe9167 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -624,7 +624,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
/*
* As per datasheet: divide register by 16 and subtract 93 to get
* degrees Celsius. hwmon requires millidegrees. Let's avoid rounding
- * errors by subtracting 93 * 16 then multiplying by 1000 / 16.
+ * errors by subtracting 93 * 16 and scaling before dividing.
*
* NOTE: The ADC registers are initialised to 0 on reset. This means
* that the temperature will read -93 *C until the chip is brought out
@@ -633,7 +633,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
* value read back from its registers will be the last value sampled
* before entering software shutdown.
*/
- *result = (reading - (93 * 16)) * (1000 / 16);
+ *result = (reading - (93 * 16)) * 1000 / 16;
return 0;
}
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index 10a2d598caa71..72a53f95d6887 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -547,6 +547,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
BIT(2), BIT(2));
snd_soc_component_update_bits(component,
+ WCD937X_AUX_AUXPA,
+ BIT(4), BIT(4));
+ snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
BIT(2), BIT(2));
snd_soc_component_update_bits(component,
@@ -562,6 +565,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
BIT(2), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_AUX_AUXPA,
+ BIT(4), 0x00);
break;
}
@@ -730,10 +736,23 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component,
WCD937X_ANA_RX_SUPPLIES,
BIT(1), BIT(1));
+ /* Enable AUX PA related RX supplies */
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(6), BIT(6));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(7), BIT(7));
enable_irq(wcd937x->aux_pdm_wd_int);
break;
case SND_SOC_DAPM_PRE_PMD:
disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(6), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(7), 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
usleep_range(2000, 2010);
@@ -2051,7 +2070,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0,
wcd937x_get_swr_port, wcd937x_set_swr_port),
-
+ SOC_SINGLE_EXT("CLSH PA Switch", WCD937X_CLSH, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DSD_L Switch", WCD937X_DSD_L, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DSD_R Switch", WCD937X_DSD_R, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0,
wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0,
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 4879f79aef292..4aa0cf49b0335 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -170,6 +170,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000);
if (ret) {
dev_err(card->dev, "Error setting codec sysclk: %d\n", ret);
+ clk_disable_unprepare(priv->mclk);
return ret;
}
} else {
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index b3d61d973ce40..8662b422eb807 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1412,7 +1412,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
link_mask |= BIT(peripherals->array[i]->bus->link_id);
link_num = hweight32(link_mask);
- links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
+ /* An empty adr_link is needed to terminate the adr_link loop */
+ links = devm_kcalloc(sdev->dev, link_num + 1, sizeof(*links), GFP_KERNEL);
if (!links)
return NULL;
diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
index 1cb99f1abc7cd..43481f387c446 100644
--- a/sound/soc/spacemit/k1_i2s.c
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -93,8 +93,8 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val;
sscr_val = SSCR_TRAIL | SSCR_FRF_PSP;
- ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 5) |
- FIELD_PREP(SSFCR_FIELD_RFT, 5) |
+ ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 0xF) |
+ FIELD_PREP(SSFCR_FIELD_RFT, 0xF) |
SSFCR_RSRE | SSFCR_TSRE;
ssrwt_val = SSRWT_RWOT;
sspsp_val = SSPSP_SFRMP;
@@ -106,6 +106,37 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
writel(0, i2s->base + SSINTEN);
}
+static int spacemit_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 2, 2);
+ snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FMTBIT_S16_LE);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, 1);
+ snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FMTBIT_S32_LE);
+ break;
+ default:
+ dev_dbg(i2s->dev, "unexpected format type");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -157,22 +188,9 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
dma_data->maxburst = 32;
dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
}
-
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- 1, 2);
- snd_pcm_hw_constraint_mask64(substream->runtime,
- SNDRV_PCM_HW_PARAM_FORMAT,
- SNDRV_PCM_FMTBIT_S16_LE);
break;
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- 1, 1);
- snd_pcm_hw_constraint_mask64(substream->runtime,
- SNDRV_PCM_HW_PARAM_FORMAT,
- SNDRV_PCM_FMTBIT_S32_LE);
break;
default:
dev_dbg(i2s->dev, "unexpected format type");
@@ -303,6 +321,7 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.probe = spacemit_i2s_dai_probe,
.remove = spacemit_i2s_dai_remove,
+ .startup = spacemit_i2s_startup,
.hw_params = spacemit_i2s_hw_params,
.set_sysclk = spacemit_i2s_set_sysclk,
.set_fmt = spacemit_i2s_set_fmt,
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 3f396c87802ed..1c18ef6971c09 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# Tegra platform Support
snd-soc-tegra-pcm-y := tegra_pcm.o
-snd-soc-tegra-utils-y += tegra_asoc_utils.o
snd-soc-tegra20-ac97-y := tegra20_ac97.o
snd-soc-tegra20-das-y := tegra20_das.o
snd-soc-tegra20-i2s-y := tegra20_i2s.o
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 8af0c04041ee3..b20aae0caf60a 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -366,7 +366,7 @@ static int setup_card(struct snd_usb_caiaqdev *cdev)
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
ret = snd_usb_caiaq_input_init(cdev);
- if (ret < 0) {
+ if (ret < 0 && ret != -ENODEV) {
dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
return ret;
}
@@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
cdev = caiaqdev(card);
cdev->chip.dev = usb_get_dev(usb_dev);
+ card->private_free = card_free;
cdev->chip.card = card;
cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct));
@@ -511,10 +512,9 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
cdev->vendor_name, cdev->product_name, usbpath);
- card->private_free = card_free;
err = setup_card(cdev);
if (err < 0)
- return err;
+ goto err_kill_urb;
return 0;
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index a9130891bb696..5c70fdf61cc13 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -804,7 +804,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
default:
/* no input methods supported on this device */
- ret = -EINVAL;
+ ret = -ENODEV;
goto exit_free_idev;
}
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 49b3dd8d827da..d129b42eb979d 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -974,6 +974,13 @@ static int detect_usb_format(struct ua101 *ua)
ua->capture.channels = fmt_capture->bNrChannels;
ua->playback.channels = fmt_playback->bNrChannels;
+ if (!ua->capture.channels || !ua->playback.channels) {
+ dev_err(&ua->dev->dev,
+ "invalid channel count: capture %u, playback %u\n",
+ ua->capture.channels, ua->playback.channels);
+ return -EINVAL;
+ }
+
ua->capture.frame_bytes =
fmt_capture->bSubframeSize * ua->capture.channels;
ua->playback.frame_bytes =
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 85653112e7f3b..5fba456eb4a96 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1190,6 +1190,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
cval->res = 1;
}
break;
+
+ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */
+ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */
+ if (!strcmp(kctl->id.name, "PCM Playback Volume")) {
+ usb_audio_info(chip,
+ "set volume quirk for PDP Riffmaster for PS4/PS5\n");
+ cval->min = -2560; /* Mute under it */
+ }
+ break;
+
case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */
if (!strcmp(kctl->id.name, "PCM Playback Volume")) {
usb_audio_info(chip,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 803e03d4d77b8..4e9cfff4047fc 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2652,6 +2652,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+
+#endif /* disabled */
+
{
/*
* The AudioBox USB advertises S24_3LE as the only supported format
@@ -2700,7 +2703,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
-#endif /* disabled */
{
/*
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 7b803ad58487f..0b4ecc2c6bcc4 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -125,7 +125,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
snd_usb_audioformat_set_sync_ep(chip, fp);
- err = snd_usb_add_audio_stream(chip, stream, fp);
+ err = snd_usb_add_audio_stream(chip, stream, fp, NULL);
if (err < 0)
return err;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 2532bf97e05e0..b2c5c8198281a 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
static void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
struct audioformat *fp,
- struct snd_usb_power_domain *pd)
+ struct snd_usb_power_domain **pdptr)
{
struct snd_usb_substream *subs = &as->substream[stream];
@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
if (fp->channels > subs->channels_max)
subs->channels_max = fp->channels;
- if (pd) {
- subs->str_pd = pd;
+ if (pdptr && *pdptr) {
+ subs->str_pd = *pdptr;
+ *pdptr = NULL; /* assigned */
/* Initialize Power Domain to idle status D1 */
- snd_usb_power_domain_set(subs->stream->chip, pd,
+ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd,
UAC3_PD_STATE_D1);
}
@@ -352,6 +353,8 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
if (len < sizeof(*cs_desc))
break;
cs_len = le16_to_cpu(cs_desc->wLength);
+ if (cs_len < sizeof(*cs_desc))
+ break;
if (len < cs_len)
break;
cs_type = cs_desc->bSegmentType;
@@ -492,11 +495,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
* if not, create a new pcm stream. note, fp is added to the substream
* fmt_list and will be freed on the chip instance release. do not free
* fp or do remove it from the substream fmt_list to avoid double-free.
+ *
+ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets
+ * assigned to the stream, *pdptr is cleared to NULL upon return.
*/
-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp,
- struct snd_usb_power_domain *pd)
+int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+ int stream,
+ struct audioformat *fp,
+ struct snd_usb_power_domain **pdptr)
{
struct snd_usb_stream *as;
@@ -529,7 +535,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
return err;
- snd_usb_init_substream(as, stream, fp, pd);
+ snd_usb_init_substream(as, stream, fp, pdptr);
return add_chmap(as->pcm, stream, subs);
}
@@ -558,7 +564,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
else
strscpy(pcm->name, "USB Audio");
- snd_usb_init_substream(as, stream, fp, pd);
+ snd_usb_init_substream(as, stream, fp, pdptr);
/*
* Keep using head insertion for M-Audio Audiophile USB (tm) which has a
@@ -576,21 +582,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
return add_chmap(pcm, stream, &as->substream[stream]);
}
-int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp)
-{
- return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
-}
-
-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp,
- struct snd_usb_power_domain *pd)
-{
- return __snd_usb_add_audio_stream(chip, stream, fp, pd);
-}
-
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
int protocol, int iface_no)
@@ -1003,7 +994,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
* and request Cluster Descriptor
*/
wLength = le16_to_cpu(hc_header.wLength);
- if (wLength < sizeof(cluster))
+ if (wLength < sizeof(*cluster))
return NULL;
cluster = kzalloc(wLength, GFP_KERNEL);
if (!cluster)
@@ -1113,8 +1104,7 @@ found_clock:
}
}
- if (pd)
- *pd_out = pd;
+ *pd_out = pd;
return fp;
}
@@ -1129,7 +1119,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
struct usb_interface_descriptor *altsd;
int i, altno, err, stream;
struct audioformat *fp = NULL;
- struct snd_usb_power_domain *pd = NULL;
bool set_iface_first;
int num, protocol;
@@ -1171,6 +1160,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
continue;
+ /* pd may be allocated at snd_usb_get_audioformat_uac3() and
+ * assigned at snd_usb_add_audio_stream(); otherwise it'll be
+ * freed automatically by cleanup at each loop.
+ */
+ struct snd_usb_power_domain *pd __free(kfree) = NULL;
+
/*
* Roland audio streaming interfaces are marked with protocols
* 0/1/2, but are UAC 1 compatible.
@@ -1226,23 +1221,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
*has_non_pcm = true;
if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) {
audioformat_free(fp);
- kfree(pd);
fp = NULL;
- pd = NULL;
continue;
}
snd_usb_audioformat_set_sync_ep(chip, fp);
dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
- if (protocol == UAC_VERSION_3)
- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
- else
- err = snd_usb_add_audio_stream(chip, stream, fp);
-
+ err = snd_usb_add_audio_stream(chip, stream, fp, &pd);
if (err < 0) {
audioformat_free(fp);
- kfree(pd);
return err;
}
diff --git a/sound/usb/stream.h b/sound/usb/stream.h
index d92e18d5818fe..61b9a133da018 100644
--- a/sound/usb/stream.h
+++ b/sound/usb/stream.h
@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
- struct audioformat *fp);
+ struct audioformat *fp,
+ struct snd_usb_power_domain **pdptr);
#endif /* __USBAUDIO_STREAM_H */