sound fixes for 7.1-rc1

Here are the rest of small updates for 7.1-rc1.  All small fixes
 mostly for device-specific issues or regressions.
 
 * Core:
 - Fix a potential data race in fasync handling
 
 * USB-audio:
 - New device support: Line6 POD HD PRO, NexiGo N930W webcam
 - Fixes for Audio Advantage Micro II SPDIF switch and E-MU sample rates
 - Limit UAC2 rate parsing to prevent potential overflows
 
 * HD-Audio:
 - Device-specific quirks for HP, Acer, and Honor laptops
 - Fix for TAS2781 SPI device abnormal sound
 - Move Intel firmware loading into probe work to avoid stalling
 
 * ASoC:
 - New support for TI TAS5832
 - Fixes for SoundWire SDCA/DisCo boolean parsing
 - Driver-specific fixes for Intel SOF, ES8311, RT1320, and PXA2xx
 
 * Misc:
 - Fixes for resource leaks and data races in 6fire, caiaq, als4000,
   and pcmtest drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmnqD8QOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE+rBA//fmPM0+DdrIGvI/62mQmpCeUcOt4Ijtu53/lw
 AL1P7aex+45Mt7QfvrwJdMhXb5EZ+Pm7Fh8/+gf3gaC8Z9oRmFzkhAZMe+ne20Uu
 CekPqDVJ55AO5enVGV2L7Lz9Hy8BQ3QqYBVh/7n25k44pYdYmfj/YNUKi8PoaQiS
 ddijA4mrhPOUIIR8QWp950R6mU4sesVROC+ni+b3HqMXNOHo4+iKvTI4gvHN3JLJ
 HfmLiqTgo04tmDTUJWSTW5n9PmW7+8tzawTH6+30fA7RAHGa+rjxAI+eGRvAyCmi
 Eyzqsnp9l95fiGXozZJonOjPycrWge7uxEILO3eyLyS1YjgZ1JL97ykImEzOvn2F
 i6GlnjQUdOcWujcvZLjIDHy/kVPKdNBTTLtNh/sm/Up8zuLRRV/miWK/jBRd06cr
 f2Om/YzOVIbwYZEealiJyQjRxuNJ+x+cmCMruUmyENJsVu3Uz+7pR53rVGvqTduh
 ISz+U5m5jg6yxwEx7lamMbavkg5CCIc+phGQRBfs5SrKKn3Wo/vgEU1GH0peQq4X
 k4cr4nkMHUOCtMiMsyaaTet3pAMEFIx07zArutx05YAjMA9nVp4jsA7deEbYcZhf
 PdXCMFHeODQBDWevTdyiE1KbyBMRzFuuzAXgXaylsX1cXl5iGYzdzIzJc03g1VjT
 hEqcqRs=
 =0UEp
 -----END PGP SIGNATURE-----

Merge tag 'sound-fix-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "Here are the rest of small updates for 7.1-rc1. All small fixes mostly
  for device-specific issues or regressions.

  Core:
   - Fix a potential data race in fasync handling

  USB-audio:
   - New device support: Line6 POD HD PRO, NexiGo N930W webcam
   - Fixes for Audio Advantage Micro II SPDIF switch and E-MU sample
     rates
   - Limit UAC2 rate parsing to prevent potential overflows

  HD-Audio:
   - Device-specific quirks for HP, Acer, and Honor laptops
   - Fix for TAS2781 SPI device abnormal sound
   - Move Intel firmware loading into probe work to avoid stalling

  ASoC:
   - New support for TI TAS5832
   - Fixes for SoundWire SDCA/DisCo boolean parsing
   - Driver-specific fixes for Intel SOF, ES8311, RT1320, and PXA2xx

  Misc:
   - Fixes for resource leaks and data races in 6fire, caiaq, als4000,
     and pcmtest drivers"

* tag 'sound-fix-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (41 commits)
  Revert "ALSA: pcmtest: fix reference leak on failed device registration"
  ASoC: tas2781: Add tas5832 support
  ASoC: dt-bindings: ti,tas2781: Add TAS5832 support
  ALSA: usb-audio: Fix Audio Advantage Micro II SPDIF switch
  ALSA: usb-audio: Avoid false E-MU sample-rate notifications
  ASoC: sdw_utils: cs42l43: allow spk component names to be combined
  ASoC: qcom: x1e80100: limit speaker volumes
  ALSA: hda/realtek - Add mute LED support for HP Victus 15-fa2xxx
  ALSA: pcmtest: Fix resource leaks in module init error paths
  ALSA: usb-audio/line6: Add support for POD HD PRO
  ALSA: hda/realtek: Add LED fixup for HP EliteBook 6 G2a Laptops
  ASoC: SDCA: Fix reading of mipi-sdca-control-deferrable
  regmap: sdw-mbq: Allow defers on undeferrable controls
  Revert "ALSA: usb-audio: Add quirk for SmartlinkTechnology M01"
  ALSA: als4000: Fix capture trigger chip->mode race
  ALSA: core: Fix potential data race at fasync handling
  ALSA: hda/tas2781: Fix sound abnormal issue on some SPI device
  ALSA: hda/realtek: add quirk for Acer Nitro 16 AN16-41
  ALSA: caiaq: Fix control_put() result and cache rollback
  ALSA: pcmtest: fix reference leak on failed device registration
  ...
This commit is contained in:
Linus Torvalds 2026-04-24 11:49:20 -07:00
commit 1fe93b2a2a
32 changed files with 339 additions and 258 deletions

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2022 - 2025 Texas Instruments Incorporated
# Copyright (C) 2022 - 2026 Texas Instruments Incorporated
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tas2781.yaml#
@ -107,6 +107,9 @@ properties:
ti,tas5830: 65-W Stereo, Digital Input, High Efficiency Closed-Loop
Class-D Amplifier with Class-H Algorithm
ti,tas5832: 81-W Stereo, Digital Input, High Efficiency Closed-Loop
Class-D Amplifier with Class-H Algorithm
oneOf:
- items:
- enum:
@ -128,6 +131,7 @@ properties:
- ti,tas5827
- ti,tas5828
- ti,tas5830
- ti,tas5832
- const: ti,tas2781
- enum:
- ti,tas2781
@ -264,6 +268,7 @@ allOf:
- ti,tas5827
- ti,tas5828
- ti,tas5830
- ti,tas5832
then:
properties:
reg:

View File

@ -74,7 +74,7 @@ static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
unsigned int reg, unsigned int val,
int mbq_size, bool deferrable)
int mbq_size)
{
int shift = mbq_size * BITS_PER_BYTE;
int ret;
@ -88,17 +88,14 @@ static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
return ret;
}
ret = sdw_write_no_pm(slave, reg, val & 0xff);
if (deferrable && ret == -ENODATA)
return -EAGAIN;
return ret;
return sdw_write_no_pm(slave, reg, val & 0xff);
}
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
{
struct regmap_mbq_context *ctx = context;
struct sdw_slave *slave = ctx->sdw;
struct device *dev = ctx->dev;
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
int ret;
@ -113,13 +110,16 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
* process a single wait/timeout on function busy and a single retry
* of the transaction.
*/
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, deferrable);
if (ret == -EAGAIN) {
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size);
if (ret == -ENODATA) {
if (!deferrable)
dev_warn(dev, "Defer on undeferrable control: %x\n", reg);
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
if (ret)
return ret;
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, false);
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size);
}
return ret;
@ -127,18 +127,14 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
static int regmap_sdw_mbq_read_impl(struct sdw_slave *slave,
unsigned int reg, unsigned int *val,
int mbq_size, bool deferrable)
int mbq_size)
{
int shift = BITS_PER_BYTE;
int read;
read = sdw_read_no_pm(slave, reg);
if (read < 0) {
if (deferrable && read == -ENODATA)
return -EAGAIN;
if (read < 0)
return read;
}
*val = read;
@ -158,6 +154,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
{
struct regmap_mbq_context *ctx = context;
struct sdw_slave *slave = ctx->sdw;
struct device *dev = ctx->dev;
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
int ret;
@ -172,13 +169,16 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
* process a single wait/timeout on function busy and a single retry
* of the transaction.
*/
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, deferrable);
if (ret == -EAGAIN) {
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
if (ret == -ENODATA) {
if (!deferrable)
dev_warn(dev, "Defer on undeferable control: %x\n", reg);
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
if (ret)
return ret;
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, false);
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
}
return ret;

View File

@ -131,6 +131,7 @@ enum audio_device {
TAS5827,
TAS5828,
TAS5830,
TAS5832,
TAS_OTHERS,
};

View File

@ -331,12 +331,15 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
if (dev->dev.of_node) {
/* Assert reset using GPIOD_OUT_HIGH, because reset is GPIO_ACTIVE_LOW */
rst_gpio = devm_gpiod_get(&dev->dev, "reset", GPIOD_OUT_HIGH);
ret = PTR_ERR(rst_gpio);
if (ret == -ENOENT)
reset_gpio = -1;
else if (ret)
return ret;
reset_gpio = desc_to_gpio(rst_gpio);
if (IS_ERR(rst_gpio)) {
ret = PTR_ERR(rst_gpio);
if (ret == -ENOENT)
reset_gpio = -1;
else if (ret)
return ret;
} else {
reset_gpio = desc_to_gpio(rst_gpio);
}
} else {
if (cpu_is_pxa27x())
reset_gpio = 113;

View File

@ -100,14 +100,18 @@ static LIST_HEAD(snd_fasync_list);
static void snd_fasync_work_fn(struct work_struct *work)
{
struct snd_fasync *fasync;
int signal, poll;
spin_lock_irq(&snd_fasync_lock);
while (!list_empty(&snd_fasync_list)) {
fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
list_del_init(&fasync->list);
if (!fasync->on)
continue;
signal = fasync->signal;
poll = fasync->poll;
spin_unlock_irq(&snd_fasync_lock);
if (fasync->on)
kill_fasync(&fasync->fasync, fasync->signal, fasync->poll);
kill_fasync(&fasync->fasync, signal, poll);
spin_lock_irq(&snd_fasync_lock);
}
spin_unlock_irq(&snd_fasync_lock);
@ -158,7 +162,10 @@ void snd_fasync_free(struct snd_fasync *fasync)
{
if (!fasync)
return;
fasync->on = 0;
scoped_guard(spinlock_irq, &snd_fasync_lock)
list_del_init(&fasync->list);
flush_work(&snd_fasync_work);
kfree(fasync);
}

View File

@ -754,13 +754,22 @@ static int __init mod_init(void)
err = init_debug_files(buf_allocated);
if (err)
return err;
goto err_free_patterns;
err = platform_device_register(&pcmtst_pdev);
if (err)
return err;
goto err_clear_debug;
err = platform_driver_register(&pcmtst_pdrv);
if (err)
if (err) {
platform_device_unregister(&pcmtst_pdev);
goto err_clear_debug;
}
return 0;
err_clear_debug:
clear_debug_files();
err_free_patterns:
free_pattern_buffers();
return err;
}

View File

@ -199,7 +199,7 @@ struct vx_cmd_info {
void vx_init_rmh(struct vx_rmh *rmh, unsigned int cmd);
/**
* vx_send_pipe_cmd_params - fill first command word for pipe commands
* vx_set_pipe_cmd_params - fill first command word for pipe commands
* @rmh: the rmh to be modified
* @is_capture: 0 = playback, 1 = capture operation
* @param1: first pipe-parameter

View File

@ -4111,6 +4111,7 @@ enum {
ALC245_FIXUP_ACER_MICMUTE_LED,
ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED,
ALC236_FIXUP_HP_DMIC,
ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@ -6653,6 +6654,16 @@ static const struct hda_fixup alc269_fixups[] = {
{ 0x12, 0x90a60160 }, /* use as internal mic */
{ }
},
},
[ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x14, 0x90170111 },
{ 0x19, 0x03a1113c },
{ 0x1a, 0x22a190a0 },
{ 0x1b, 0x90170110 },
{ }
}
}
};
@ -6706,6 +6717,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, 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),
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
@ -7142,6 +7154,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8dcd, "HP Victus 15-fa2xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
@ -7214,6 +7227,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f3c, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f3d, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f41, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
@ -7751,6 +7766,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK),
SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO),
SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC),
SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@ -7971,6 +7987,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"},
{.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
{.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"},
{.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"},
{}
};
#define ALC225_STANDARD_PINS \

View File

@ -788,6 +788,7 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
}
if (strstr(dev_name(&spi->dev), "TXNW2781")) {
device_name = "TXNW2781";
tas_hda->priv->chip_id = TAS2781;
} else {
dev_err(tas_priv->dev, "Unmatched spi dev %s\n",
dev_name(&spi->dev));

View File

@ -127,10 +127,6 @@ struct azx {
unsigned int beep_mode;
bool ctl_dev_id;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
const struct firmware *fw;
#endif
/* flags */
int bdl_pos_adj;
unsigned int running:1;

View File

@ -1385,9 +1385,6 @@ static void azx_free(struct azx *chip)
azx_free_streams(chip);
snd_hdac_bus_exit(bus);
#ifdef CONFIG_SND_HDA_PATCH_LOADER
release_firmware(chip->fw);
#endif
display_power(chip, false);
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
@ -2037,24 +2034,6 @@ static int azx_first_init(struct azx *chip)
return 0;
}
#ifdef CONFIG_SND_HDA_PATCH_LOADER
/* callback from request_firmware_nowait() */
static void azx_firmware_cb(const struct firmware *fw, void *context)
{
struct snd_card *card = context;
struct azx *chip = card->private_data;
if (fw)
chip->fw = fw;
else
dev_err(card->dev, "Cannot load firmware, continue without patching\n");
if (!chip->disabled) {
/* continue probing */
azx_probe_continue(chip);
}
}
#endif
static int disable_msi_reset_irq(struct azx *chip)
{
struct hdac_bus *bus = azx_bus(chip);
@ -2131,7 +2110,6 @@ static int azx_probe(struct pci_dev *pci,
struct snd_card *card;
struct hda_intel *hda;
struct azx *chip;
bool schedule_probe;
int dev;
int err;
@ -2227,22 +2205,7 @@ static int azx_probe(struct pci_dev *pci,
chip->disabled = true;
}
schedule_probe = !chip->disabled;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
dev_info(card->dev, "Applying patch firmware '%s'\n",
patch[dev]);
err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
&pci->dev, GFP_KERNEL, card,
azx_firmware_cb);
if (err < 0)
goto out_free;
schedule_probe = false; /* continued in azx_firmware_cb() */
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
if (schedule_probe)
if (!chip->disabled)
schedule_delayed_work(&hda->probe_work, 0);
set_bit(dev, probed_devs);
@ -2371,11 +2334,20 @@ static int azx_probe_continue(struct azx *chip)
}
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (chip->fw) {
err = snd_hda_load_patch(&chip->bus, chip->fw->size,
chip->fw->data);
if (err < 0)
goto out_free;
if (patch[dev] && *patch[dev]) {
const struct firmware *fw = NULL;
dev_info(&pci->dev, "Applying patch firmware '%s'\n",
patch[dev]);
if (request_firmware(&fw, patch[dev], &pci->dev) < 0) {
dev_err(&pci->dev,
"Cannot load firmware, continue without patching\n");
} else {
err = snd_hda_load_patch(&chip->bus, fw->size, fw->data);
release_firmware(fw);
if (err < 0)
goto out_free;
}
}
#endif

View File

@ -421,30 +421,26 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
int result = 0;
/* FIXME race condition in here!!!
chip->mode non-atomic update gets consistently protected
by reg_lock always, _except_ for this place!!
Probably need to take reg_lock as outer (or inner??) lock, too.
(or serialize both lock operations? probably not, though... - racy?)
*/
guard(spinlock)(&chip->mixer_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
chip->mode |= SB_RATE_LOCK_CAPTURE;
snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
capture_cmd(chip));
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
chip->mode &= ~SB_RATE_LOCK_CAPTURE;
snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
capture_cmd(chip));
break;
default:
result = -EINVAL;
break;
guard(spinlock)(&chip->reg_lock);
scoped_guard(spinlock, &chip->mixer_lock) {
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
chip->mode |= SB_RATE_LOCK_CAPTURE;
snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
capture_cmd(chip));
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
chip->mode &= ~SB_RATE_LOCK_CAPTURE;
snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
capture_cmd(chip));
break;
default:
result = -EINVAL;
break;
}
}
return result;
}

View File

@ -761,6 +761,7 @@ static int es8311_set_bias_level(struct snd_soc_component *component,
{
struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
case SND_SOC_BIAS_ON:
@ -769,17 +770,21 @@ static int es8311_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
int ret = clk_prepare_enable(es8311->mclk);
ret = clk_prepare_enable(es8311->mclk);
if (ret) {
dev_err(component->dev,
"unable to prepare mclk\n");
return ret;
}
snd_soc_component_update_bits(
component, ES8311_SYS3,
ES8311_SYS3_PDN_VMIDSEL_MASK,
ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
ret = snd_soc_component_update_bits(
component, ES8311_SYS3,
ES8311_SYS3_PDN_VMIDSEL_MASK,
ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
if (ret < 0) {
clk_disable_unprepare(es8311->mclk);
return ret;
}
}
break;
@ -862,13 +867,18 @@ static int es8311_suspend(struct snd_soc_component *component)
static int es8311_resume(struct snd_soc_component *component)
{
struct es8311_priv *es8311;
int ret;
es8311 = snd_soc_component_get_drvdata(component);
es8311_reset(component, false);
regcache_cache_only(es8311->regmap, false);
regcache_sync(es8311->regmap);
ret = regcache_sync(es8311->regmap);
if (ret) {
dev_err(component->dev, "unable to sync regcache\n");
return ret;
}
return 0;
}

View File

@ -1498,6 +1498,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
}
if (!retry && !(value & 0x40)) {
dev_err(dev, "%s: RAE is not ready to load\n", __func__);
release_firmware(rae_fw);
return -ETIMEDOUT;
}

View File

@ -2487,7 +2487,7 @@ static int tas2781_cali_preproc(struct tasdevice_priv *priv, int i)
if (spec == NULL)
return -ENOMEM;
priv->tasdevice[i].cali_specific = spec;
rc = tasdevice_dev_bulk_read(priv, i, p->r0_reg, r0_deflt, 4);
rc = priv->dev_bulk_read(priv, i, p->r0_reg, r0_deflt, 4);
if (rc < 0) {
dev_err(priv->dev, "invalid RE from %d = %d\n", i, rc);
return rc;
@ -2511,9 +2511,8 @@ static int tas2781_cali_preproc(struct tasdevice_priv *priv, int i)
TASDEVICE_REG(0, 0x1b, 0x34) :
TASDEVICE_REG(0, 0x18, 0x1c);
rc = tasdevice_dev_bulk_read(priv, i,
spec->sin_gni_reg,
spec->sin_gni, 4);
rc = priv->dev_bulk_read(priv, i, spec->sin_gni_reg,
spec->sin_gni, 4);
if (rc < 0) {
dev_err(priv->dev, "wrong sinegaini %d = %d\n",
i, rc);

View File

@ -119,10 +119,10 @@ static const struct i2c_device_id tasdevice_id[] = {
{ "tas5827", TAS5827 },
{ "tas5828", TAS5828 },
{ "tas5830", TAS5830 },
{ "tas5832", TAS5832 },
{}
};
#ifdef CONFIG_OF
static const struct of_device_id tasdevice_of_match[] = {
{ .compatible = "ti,tas2020", .data = &tasdevice_id[TAS2020] },
{ .compatible = "ti,tas2118", .data = &tasdevice_id[TAS2118] },
@ -143,10 +143,10 @@ static const struct of_device_id tasdevice_of_match[] = {
{ .compatible = "ti,tas5827", .data = &tasdevice_id[TAS5827] },
{ .compatible = "ti,tas5828", .data = &tasdevice_id[TAS5828] },
{ .compatible = "ti,tas5830", .data = &tasdevice_id[TAS5830] },
{ .compatible = "ti,tas5832", .data = &tasdevice_id[TAS5832] },
{},
};
MODULE_DEVICE_TABLE(of, tasdevice_of_match);
#endif
/**
* tas2781_digital_getvol - get the volum control
@ -1746,6 +1746,7 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
case TAS5827:
case TAS5828:
case TAS5830:
case TAS5832:
/* If DSP FW fail, DSP kcontrol won't be created. */
tasdevice_dsp_remove(tas_priv);
}
@ -1917,6 +1918,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec)
case TAS5827:
case TAS5828:
case TAS5830:
case TAS5832:
p = (struct snd_kcontrol_new *)tas5825_snd_controls;
size = ARRAY_SIZE(tas5825_snd_controls);
break;
@ -2083,7 +2085,6 @@ static void tasdevice_i2c_remove(struct i2c_client *client)
tasdevice_remove(tas_priv);
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id tasdevice_acpi_match[] = {
{ "TXNW2020", (kernel_ulong_t)&tasdevice_id[TAS2020] },
{ "TXNW2118", (kernel_ulong_t)&tasdevice_id[TAS2118] },
@ -2104,19 +2105,17 @@ static const struct acpi_device_id tasdevice_acpi_match[] = {
{ "TXNW5827", (kernel_ulong_t)&tasdevice_id[TAS5827] },
{ "TXNW5828", (kernel_ulong_t)&tasdevice_id[TAS5828] },
{ "TXNW5830", (kernel_ulong_t)&tasdevice_id[TAS5830] },
{ "TXNW5832", (kernel_ulong_t)&tasdevice_id[TAS5832] },
{},
};
MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
#endif
static struct i2c_driver tasdevice_i2c_driver = {
.driver = {
.name = "tasdev-codec",
.of_match_table = of_match_ptr(tasdevice_of_match),
#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
#endif
.of_match_table = tasdevice_of_match,
.acpi_match_table = tasdevice_acpi_match,
},
.probe = tasdevice_i2c_probe,
.remove = tasdevice_i2c_remove,

View File

@ -27,10 +27,29 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_card *card = rtd->card;
struct snd_soc_jack *dp_jack = NULL;
int dp_pcm_id = 0;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
/*
* Set limit of -3 dB on Digital Volume and 0 dB on PA Volume
* to reduce the risk of speaker damage until we have active
* speaker protection in place.
*/
snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", 81);
snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", 81);
snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", 81);
snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", 81);
snd_soc_limit_volume(card, "SpkrLeft PA Volume", 6);
snd_soc_limit_volume(card, "SpkrRight PA Volume", 6);
snd_soc_limit_volume(card, "WooferLeft PA Volume", 6);
snd_soc_limit_volume(card, "TweeterLeft PA Volume", 6);
snd_soc_limit_volume(card, "WooferRight PA Volume", 6);
snd_soc_limit_volume(card, "TweeterRight PA Volume", 6);
break;
case DISPLAY_PORT_RX_0:
dp_pcm_id = 0;
dp_jack = &data->dp_jack[dp_pcm_id];

View File

@ -1006,8 +1006,11 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->has_fixed = true;
fallthrough;
case SDCA_ACCESS_MODE_RO:
control->deferrable = fwnode_property_read_bool(control_node,
"mipi-sdca-control-deferrable");
ret = fwnode_property_read_u32(control_node,
"mipi-sdca-control-deferrable",
&tmp);
if (ret == 0)
control->deferrable = !!tmp;
break;
default:
break;

View File

@ -40,12 +40,6 @@ static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s spk:cs35l56-bridge",
card->components);
if (!card->components)
return -ENOMEM;
ret = snd_soc_dapm_new_controls(dapm, bridge_widgets,
ARRAY_SIZE(bridge_widgets));
if (ret) {

View File

@ -107,21 +107,11 @@ EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, "SND_SOC_SDW_UTILS");
int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
struct snd_soc_component *component = dai->component;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
if (!(ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)) {
/* Will be set by the bridge code in this case */
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s spk:cs42l43-spk",
card->components);
if (!card->components)
return -ENOMEM;
}
ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume",
CS42L43_SPK_VOLUME_0DB);
if (ret)

View File

@ -758,6 +758,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
{
.direction = {true, false},
.codec_name = "cs42l43-codec",
.component_name = "cs42l43-spk",
.dai_name = "cs42l43-dp6",
.dai_type = SOC_SDW_DAI_TYPE_AMP,
.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
@ -1104,6 +1105,7 @@ static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *
int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct asoc_sdw_codec_info *codec_info;
struct snd_soc_dai *dai;
@ -1179,16 +1181,26 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
/* Generate the spk component string for card->components string */
if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP &&
codec_info->dais[dai_index].component_name) {
const char *component;
/*
* For the special case of cs42l43 with sidecar amps, use only
* "cs35l56-bridge" as the component name in card->components
*/
if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS &&
!strcmp(codec_info->dais[dai_index].component_name, "cs42l43-spk"))
component = "cs35l56-bridge";
else
component = codec_info->dais[dai_index].component_name;
if (strlen (spk_components) == 0)
spk_components =
devm_kasprintf(card->dev, GFP_KERNEL, "%s",
codec_info->dais[dai_index].component_name);
devm_kasprintf(card->dev, GFP_KERNEL, "%s", component);
else
/* Append component name to spk_components */
spk_components =
devm_kasprintf(card->dev, GFP_KERNEL,
"%s+%s", spk_components,
codec_info->dais[dai_index].component_name);
"%s+%s", spk_components, component);
}
codec_info->dais[dai_index].rtd_init_done = true;

View File

@ -48,6 +48,7 @@ const struct sof_intel_dsp_desc nvl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_4_0,
.platform = "nvl",
};
const struct sof_intel_dsp_desc nvl_s_chip_info = {
@ -72,6 +73,7 @@ const struct sof_intel_dsp_desc nvl_s_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_4_0,
.platform = "nvl",
};
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");

View File

@ -31,7 +31,6 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */
static struct sfire_chip *chips[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
static struct usb_device *devices[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the 6fire sound device");
@ -44,32 +43,28 @@ static DEFINE_MUTEX(register_mutex);
static void usb6fire_chip_abort(struct sfire_chip *chip)
{
if (chip) {
if (chip->pcm)
usb6fire_pcm_abort(chip);
if (chip->midi)
usb6fire_midi_abort(chip);
if (chip->comm)
usb6fire_comm_abort(chip);
if (chip->control)
usb6fire_control_abort(chip);
}
if (chip->pcm)
usb6fire_pcm_abort(chip);
if (chip->midi)
usb6fire_midi_abort(chip);
if (chip->comm)
usb6fire_comm_abort(chip);
if (chip->control)
usb6fire_control_abort(chip);
}
static void usb6fire_card_free(struct snd_card *card)
{
struct sfire_chip *chip = card->private_data;
if (chip) {
if (chip->pcm)
usb6fire_pcm_destroy(chip);
if (chip->midi)
usb6fire_midi_destroy(chip);
if (chip->comm)
usb6fire_comm_destroy(chip);
if (chip->control)
usb6fire_control_destroy(chip);
}
if (chip->pcm)
usb6fire_pcm_destroy(chip);
if (chip->midi)
usb6fire_midi_destroy(chip);
if (chip->comm)
usb6fire_comm_destroy(chip);
if (chip->control)
usb6fire_control_destroy(chip);
}
static int usb6fire_chip_probe(struct usb_interface *intf,
@ -83,21 +78,18 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
struct snd_card *card = NULL;
/* look if we already serve this card and return if so */
scoped_guard(mutex, &register_mutex) {
for (i = 0; i < SNDRV_CARDS; i++) {
if (devices[i] == device) {
if (chips[i])
chips[i]->intf_count++;
usb_set_intfdata(intf, chips[i]);
return 0;
} else if (!devices[i] && regidx < 0)
regidx = i;
}
if (regidx < 0) {
dev_err(&intf->dev, "too many cards registered.\n");
return -ENODEV;
}
devices[regidx] = device;
guard(mutex)(&register_mutex);
for (i = 0; i < SNDRV_CARDS; i++) {
if (chips[i] && chips[i]->dev == device) {
chips[i]->intf_count++;
usb_set_intfdata(intf, chips[i]);
return 0;
} else if (!chips[i] && regidx < 0)
regidx = i;
}
if (regidx < 0) {
dev_err(&intf->dev, "too many cards registered.\n");
return -ENODEV;
}
/* check, if firmware is present on device, upload it if not */
@ -124,7 +116,6 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
device->bus->busnum, device->devnum);
chip = card->private_data;
chips[regidx] = chip;
chip->dev = device;
chip->regidx = regidx;
chip->intf_count = 1;
@ -152,7 +143,10 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
dev_err(&intf->dev, "cannot register card.");
goto destroy_chip;
}
usb_set_intfdata(intf, chip);
chips[regidx] = chip;
return 0;
destroy_chip:
@ -165,30 +159,31 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf)
struct sfire_chip *chip;
struct snd_card *card;
guard(mutex)(&register_mutex);
chip = usb_get_intfdata(intf);
if (chip) { /* if !chip, fw upload has been performed */
chip->intf_count--;
if (!chip->intf_count) {
scoped_guard(mutex, &register_mutex) {
devices[chip->regidx] = NULL;
chips[chip->regidx] = NULL;
}
/* if !chip, fw upload has been performed */
if (!chip)
return;
/*
* Save card pointer before teardown.
* snd_card_free_when_closed() may free card (and
* the embedded chip) immediately, so it must be
* called last and chip must not be accessed after.
*/
card = chip->card;
chip->shutdown = true;
if (card)
snd_card_disconnect(card);
usb6fire_chip_abort(chip);
if (card)
snd_card_free_when_closed(card);
}
}
chip->intf_count--;
if (chip->intf_count)
return;
chips[chip->regidx] = NULL;
/*
* Save card pointer before teardown.
* snd_card_free_when_closed() may free card (and
* the embedded chip) immediately, so it must be
* called last and chip must not be accessed after.
*/
card = chip->card;
chip->shutdown = true;
if (card)
snd_card_disconnect(card);
usb6fire_chip_abort(chip);
if (card)
snd_card_free_when_closed(card);
}
static const struct usb_device_id device_table[] = {

View File

@ -290,15 +290,17 @@ static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
int vol0 = ucontrol->value.integer.value[0] - 15;
int vol1 = ucontrol->value.integer.value[1] - 15;
int changed = 0;
if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
if (rt->input_vol[0] != vol0) {
rt->input_vol[0] = vol0;
rt->ivol_updated &= ~(1 << 0);
changed = 1;
}
if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
if (rt->input_vol[1] != vol1) {
rt->input_vol[1] = vol1;
rt->ivol_updated &= ~(1 << 1);
changed = 1;
}

View File

@ -87,6 +87,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
int v = ucontrol->value.integer.value[0];
int ret;
unsigned char cmd;
switch (cdev->chip.usb_id) {
@ -103,6 +104,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
if (pos & CNT_INTVAL) {
int i = pos & ~CNT_INTVAL;
unsigned char old = cdev->control_state[i];
if (old == v)
return 0;
cdev->control_state[i] = v;
@ -113,10 +118,11 @@ static int control_put(struct snd_kcontrol *kcontrol,
cdev->ep8_out_buf[0] = i;
cdev->ep8_out_buf[1] = v;
usb_bulk_msg(cdev->chip.dev,
usb_sndbulkpipe(cdev->chip.dev, 8),
cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
&actual_len, 200);
ret = usb_bulk_msg(cdev->chip.dev,
usb_sndbulkpipe(cdev->chip.dev, 8),
cdev->ep8_out_buf,
sizeof(cdev->ep8_out_buf),
&actual_len, 200);
} else if (cdev->chip.usb_id ==
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) {
@ -128,21 +134,36 @@ static int control_put(struct snd_kcontrol *kcontrol,
offset = MASCHINE_BANK_SIZE;
}
snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
cdev->control_state + offset,
MASCHINE_BANK_SIZE);
ret = snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
cdev->control_state + offset,
MASCHINE_BANK_SIZE);
} else {
snd_usb_caiaq_send_command(cdev, cmd,
cdev->control_state, sizeof(cdev->control_state));
ret = snd_usb_caiaq_send_command(cdev, cmd,
cdev->control_state,
sizeof(cdev->control_state));
}
if (ret < 0) {
cdev->control_state[i] = old;
return ret;
}
} else {
if (v)
cdev->control_state[pos / 8] |= 1 << (pos % 8);
else
cdev->control_state[pos / 8] &= ~(1 << (pos % 8));
int idx = pos / 8;
unsigned char mask = 1 << (pos % 8);
unsigned char old = cdev->control_state[idx];
unsigned char val = v ? (old | mask) : (old & ~mask);
snd_usb_caiaq_send_command(cdev, cmd,
cdev->control_state, sizeof(cdev->control_state));
if (old == val)
return 0;
cdev->control_state[idx] = val;
ret = snd_usb_caiaq_send_command(cdev, cmd,
cdev->control_state,
sizeof(cdev->control_state));
if (ret < 0) {
cdev->control_state[idx] = old;
return ret;
}
}
return 1;
@ -640,4 +661,3 @@ int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
return ret;
}

View File

@ -290,7 +290,7 @@ int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev,
tmp, sizeof(tmp));
}
static void setup_card(struct snd_usb_caiaqdev *cdev)
static int setup_card(struct snd_usb_caiaqdev *cdev)
{
int ret;
char val[4];
@ -325,8 +325,10 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0);
if (!wait_event_timeout(cdev->ep1_wait_queue,
cdev->control_state[0] != 0xff, HZ))
return;
cdev->control_state[0] != 0xff, HZ)) {
dev_err(dev, "Read timeout for control state\n");
return -EINVAL;
}
/* fix up some defaults */
if ((cdev->control_state[1] != 2) ||
@ -347,33 +349,43 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
cdev->spec.num_digital_audio_out +
cdev->spec.num_digital_audio_in > 0) {
ret = snd_usb_caiaq_audio_init(cdev);
if (ret < 0)
if (ret < 0) {
dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret);
return ret;
}
}
if (cdev->spec.num_midi_in +
cdev->spec.num_midi_out > 0) {
ret = snd_usb_caiaq_midi_init(cdev);
if (ret < 0)
if (ret < 0) {
dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret);
return ret;
}
}
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
ret = snd_usb_caiaq_input_init(cdev);
if (ret < 0)
if (ret < 0) {
dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
return ret;
}
#endif
/* finally, register the card and all its sub-instances */
ret = snd_card_register(cdev->chip.card);
if (ret < 0) {
dev_err(dev, "snd_card_register() returned %d\n", ret);
snd_card_free(cdev->chip.card);
return ret;
}
ret = snd_usb_caiaq_control_init(cdev);
if (ret < 0)
if (ret < 0) {
dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);
return ret;
}
return 0;
}
static void card_free(struct snd_card *card)
@ -499,8 +511,11 @@ 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);
setup_card(cdev);
card->private_free = card_free;
err = setup_card(cdev);
if (err < 0)
return err;
return 0;
err_kill_urb:

View File

@ -470,7 +470,7 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
nr_rates++;
if (nr_rates >= MAX_NR_RATES) {
usb_audio_err(chip, "invalid uac2 rates\n");
break;
return nr_rates;
}
skip_rate:

View File

@ -28,6 +28,7 @@ enum {
LINE6_PODHD500X,
LINE6_PODHDDESKTOP,
LINE6_PODHDPROX,
LINE6_PODHDPRO,
};
struct usb_line6_podhd {
@ -442,6 +443,7 @@ static const struct usb_device_id podhd_id_table[] = {
{ LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
{ LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
{ LINE6_IF_NUM(0x415A, 0), .driver_info = LINE6_PODHDPROX },
{ LINE6_IF_NUM(0x4157, 0), .driver_info = LINE6_PODHDPRO },
{}
};
@ -542,6 +544,18 @@ static const struct line6_properties podhd_properties_table[] = {
.ep_audio_r = 0x86,
.ep_audio_w = 0x02,
},
[LINE6_PODHDPRO] = {
.id = "PODHDPRO",
.name = "POD HD PRO",
.capabilities = LINE6_CAP_PCM | LINE6_CAP_CONTROL
| LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL | LINE6_CAP_IN_NEEDS_OUT,
.altsetting = 1,
.ctrl_if = 1,
.ep_ctrl_r = 0x81,
.ep_ctrl_w = 0x01,
.ep_audio_r = 0x86,
.ep_audio_w = 0x02,
},
};
/*

View File

@ -2664,6 +2664,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
/* get min/max values */
switch (type) {
case USB_XU_CLOCK_RATE:
/*
* E-Mu USB 0404/0202/TrackerPre/0204
* samplerate control quirk
*/
cval->min = 0;
cval->max = 5;
cval->res = 1;
cval->initialized = 1;
break;
case UAC_PROCESS_UP_DOWNMIX: {
bool mode_sel = false;
@ -2687,31 +2697,17 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
cval->max = control_spec[0];
cval->res = 1;
cval->initialized = 1;
err = 0;
break;
}
err = get_min_max(cval, valinfo->min_value);
break;
fallthrough;
}
case USB_XU_CLOCK_RATE:
/*
* E-Mu USB 0404/0202/TrackerPre/0204
* samplerate control quirk
*/
cval->min = 0;
cval->max = 5;
cval->res = 1;
cval->initialized = 1;
err = 0;
break;
default:
err = get_min_max(cval, valinfo->min_value);
break;
}
if (err < 0 && err != -EAGAIN) {
usb_mixer_elem_info_free(cval);
return err;
if (err < 0 && err != -EAGAIN) {
usb_mixer_elem_info_free(cval);
return err;
}
}
err = get_cur_ctl_value(cval, cval->control << 8, &val);

View File

@ -1538,15 +1538,17 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
{
struct usb_mixer_interface *mixer;
struct usb_mixer_elem_info *cval;
int err;
int unitid = 12; /* SampleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) {
if (mixer->id_elems[unitid]) {
cval = mixer_elem_list_to_info(mixer->id_elems[unitid]);
snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
cval->control << 8,
samplerate_id);
snd_usb_mixer_notify_id(mixer, unitid);
err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
cval->control << 8,
samplerate_id);
if (!err)
snd_usb_mixer_notify_id(mixer, unitid);
break;
}
}
@ -2025,7 +2027,7 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
int err;
reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
if (reg != list->kctl->private_value)
if (reg == list->kctl->private_value)
return 0;
kcontrol->private_value = reg;

View File

@ -2474,6 +2474,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */
QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
DEVICE_FLG(0x3443, 0x930d, /* NexiGo N930W 60fps Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */

View File

@ -37,7 +37,6 @@ struct virtio_pcm_msg;
* the device side at resume.
* @msgs: Allocated I/O messages.
* @nmsgs: Number of allocated I/O messages.
* @msg_last_enqueued: Index of the last I/O message added to the virtqueue.
* @msg_count: Number of pending I/O messages in the virtqueue.
* @msg_empty: Notify when msg_count is zero.
*/