sound fixes for 7.3-rc2

A collection of small fixes since 7.3-rc1.  Quite a few fixes are
 for ALSA core for issues that have been detected by the things you
 know well.  Additionally a series of hardening for runtime PM, and
 usual quirk updates, and some other misc driver fixes are included.
 
 * Core:
 - Fixes for PCM races
 - UMP parser NULL dereference fix
 - Fix error handling in rawmidi ioctl
 
 * USB- and HD-audio:
 - Implement missing runtime PM guards across multiple interfaces
 - Fix for OOB access in US-122L MIDI driver
 - Double-free fix for CAIAQ driver
 - Quirks for HD-audio Realtek & Cirrus codecs, Conexant S3-resume,
   USB Audient devices
 
 * Others:
 - Fix of logical mistakes in dummy driver mixer and selftest code
 - Lock init fix in the legacy harmony driver
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmqaiQ0OHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE+d2Q/9EnlQ0Sr+MYS81pYzxjWNSKzvwtRw5h3B8Hjo
 bBTflzPH+iD0AI5Y0HJ31wMrkhJPSDkznQ76foZiSgTTJh85LhoG9HlZlpIxdPW4
 fNS9/N28JKRZM+qTd5P7UvGbKv9hBpMAYQPkgmAiCZ5+47oQLhgBU5THpn0Mwhxo
 JpmULLjKuSGKCf+b/SY3MY+UF7CotiQL5L5uTF83JSm8T7DdjFwzUgk6YCTzc7/b
 WbuWa5TjIg6smSzCQaip8WoE/KimLJ++zKwk8tFH2mpWcNthmTdzQGosZbp7k3l5
 G01va200DdRE7ROXdkyao7jj8FSkex23NZyQmTDYMvQz9YmGMDhsDps+Aiv11hfY
 vlwGHHHuUO/gZcjrMB+JO5MXVxsFvyNOI7L0bFMAcX8BQwcVmXLujOI+B+iY/3Ut
 TMncDaaeKDbP/dGNROVFds2nO0pUsR3Fip16Xczy4lds6QQ8XaHefUIN4jzbltHc
 hkrCKGdyXuzpBKIlSag7xE7wSAWSLGgNnRkN7614cZSK8DRJpkrtef60Uc7W8hEU
 17c9cmhOlUM6C5BvIEmdyzN6Y0tKXdJaG/gz1Wlx2iMnsNyZ9zO7ZJq5c5HU+Txl
 3559GWY4sMDtm/A/aG9daMo1Rym3dqRwqdW/DvfhLXythLCA2YRTQIG5bHunGFYU
 jok+fBc=
 =uXXN
 -----END PGP SIGNATURE-----

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

Pull sound fixes from Takashi Iwai:
 "A collection of small fixes since 7.3-rc1.

  Quite a few fixes are for ALSA core for issues that have been detected
  by the things you know well. Additionally a series of hardening for
  runtime PM, and usual quirk updates, and some other misc driver fixes
  are included.

  Core:
   - Fixes for PCM races
   - UMP parser NULL dereference fix
   - Fix error handling in rawmidi ioctl

  USB- and HD-audio:
   - Implement missing runtime PM guards across multiple interfaces
   - Fix for OOB access in US-122L MIDI driver
   - Double-free fix for CAIAQ driver
   - Quirks for HD-audio Realtek & Cirrus codecs, Conexant S3-resume,
     USB Audient devices

  Others:
   - Fix of logical mistakes in dummy driver mixer and selftest code
   - Lock init fix in the legacy harmony driver"

* tag 'sound-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (23 commits)
  ALSA: caiaq: Fix potential double-free at error path
  selftests/alsa: Fix the step check for INTEGER controls
  ALSA: hda/realtek: Fix cold-boot headset misdetection on Acer Aspire A515-57G
  ALSA: rawmidi: Return the error from snd_rawmidi_input_params()
  ALSA: ump: do not touch legacy_rmidi before it exists
  ALSA: hda/cs420x: Add CS4208 fixup for MacBookAir 7,2
  ALSA: dummy: Report a change when one capture switch channel moves
  ALSA: usb-audio: Add mixer map quirk for Audient iD24
  ALSA: hda: restore MFG widget enumeration after core split
  ALSA: usb-audio: fix OOB write in snd_usbmidi_us122l_output()
  ALSA: pcm: Serialize PCM mmap with buffer reallocation to fix page UAF
  ALSA: harmony: initialize locks before requesting IRQ
  ALSA: hda/realtek: Add quirk for VAIO VJS131
  ALSA: pcm: Fix race between non-atomic ops and trigger-start
  ALSA: hda/realtek: Add quirk for Acer Predator PHN16-72
  ALSA: hda/realtek: Add quirk for Lenovo Yoga Slim 9 14ILL10
  ALSA: hda/conexant:Fix abnormal Mic/Speaker functionality on SN6140 after S3 wake-up
  ALSA: usb-audio: Guard FCP protocol transfers
  ALSA: usb-audio: Add PM guards to RME Digiface controls
  ALSA: usb-audio: Guard Scarlett2 protocol transfers
  ...
This commit is contained in:
Linus Torvalds 2026-09-04 09:17:05 -07:00
commit 36ec09e263
19 changed files with 191 additions and 31 deletions

View File

@ -1468,6 +1468,8 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->state != SNDRV_PCM_STATE_PREPARED)
return -EBADFD;
if (atomic_read(&runtime->buffer_accessing) < 0)
return -EBADFD; /* during hw_params, hw_free or prepare */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
!snd_pcm_playback_data(substream))
return -EPIPE;
@ -4021,20 +4023,33 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
return -EINVAL;
}
runtime = substream->runtime;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (!(runtime->info & SNDRV_PCM_INFO_MMAP))
return -ENXIO;
/* don't race with buffer reallocation in hw_params/hw_free */
if (!atomic_inc_unless_negative(&runtime->buffer_accessing))
return -EBUSY;
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
err = -EBADFD;
goto out;
}
if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {
err = -ENXIO;
goto out;
}
if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
err = -EINVAL;
goto out;
}
size = area->vm_end - area->vm_start;
offset = area->vm_pgoff << PAGE_SHIFT;
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
if ((size_t)size > dma_bytes)
return -EINVAL;
if (offset > dma_bytes - size)
return -EINVAL;
if ((size_t)size > dma_bytes) {
err = -EINVAL;
goto out;
}
if (offset > dma_bytes - size) {
err = -EINVAL;
goto out;
}
area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream;
@ -4044,6 +4059,8 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
err = snd_pcm_lib_default_mmap(substream, area);
if (!err)
atomic_inc(&substream->mmap_count);
out:
atomic_dec(&runtime->buffer_accessing);
return err;
}
EXPORT_SYMBOL(snd_pcm_mmap_data);

View File

@ -785,7 +785,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
substream->framing = framing;
substream->clock_type = clock_type;
}
return 0;
return err;
}
EXPORT_SYMBOL(snd_rawmidi_input_params);

View File

@ -1335,6 +1335,8 @@ static void update_legacy_names(struct snd_ump_endpoint *ump)
{
struct snd_rawmidi *rmidi = ump->legacy_rmidi;
if (!rmidi)
return;
update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT);
update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT);
}
@ -1343,6 +1345,8 @@ static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump)
{
struct snd_rawmidi *rmidi = ump->legacy_rmidi;
if (!rmidi)
return;
snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)",
ump->core.name);
}

View File

@ -808,7 +808,7 @@ static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
left = ucontrol->value.integer.value[0] & 1;
right = ucontrol->value.integer.value[1] & 1;
guard(spinlock_irq)(&dummy->mixer_lock);
change = dummy->capture_source[addr][0] != left &&
change = dummy->capture_source[addr][0] != left ||
dummy->capture_source[addr][1] != right;
dummy->capture_source[addr][0] = left;
dummy->capture_source[addr][1] = right;

View File

@ -571,6 +571,7 @@ static const struct hda_model_fixup cs4208_models[] = {
static const struct hda_quirk cs4208_fixup_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
SND_PCI_QUIRK(0x8086, 0x7270, "MacBookAir 7,2", CS4208_MAC_AUTO),
{} /* terminator */
};
@ -583,6 +584,7 @@ static const struct hda_quirk cs4208_mac_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x7800, "MacPro 6,1", CS4208_MACMINI),
SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
SND_PCI_QUIRK(0x106b, 0x7f00, "iMac 16,1", CS4208_MBP11),
SND_PCI_QUIRK(0x8086, 0x7270, "MacBookAir 7,2", CS4208_MBA6),
{} /* terminator */
};

View File

@ -249,6 +249,25 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_
}
}
#define SN6140_S3_AFG_D0_DELAY_MS 1000
static void cx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state)
{
snd_hda_codec_write_sync(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
/*
* SN6140 may not respond to AFG D0 immediately after S3.
* Wait before the D0 verb so the power-state command itself succeeds.
*/
if (codec->core.vendor_id == 0x14f11f87 &&
power_state == AC_PWRST_D0 &&
codec->core.dev.power.power_state.event == PM_EVENT_RESUME)
msleep(SN6140_S3_AFG_D0_DELAY_MS);
snd_hda_codec_set_power_to_all(codec, fg, power_state);
}
static int cx_suspend(struct hda_codec *codec)
{
cx_auto_shutdown(codec);
@ -1308,6 +1327,7 @@ static const struct hda_codec_ops cx_codec_ops = {
.init = cx_init,
.unsol_event = snd_hda_jack_unsol_event,
.suspend = cx_suspend,
.set_power_state = cx_set_power_state,
.check_power_status = snd_hda_gen_check_power_status,
.stream_pm = snd_hda_gen_stream_pm,
};

View File

@ -2379,6 +2379,33 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
}
}
/*
* On the Acer Aspire A515-57G (and possibly other models sharing this
* board), if headphones are already inserted into the combo jack before
* the codec powers up (cold boot), the impedance-based headset-type
* sensing races and misclassifies the jack, driving the wrong output
* configuration (audible as missing center-panned/vocal content). A
* genuine physical unplug/replug after boot fixes it by forcing a fresh
* sense transient. Mirror that here on cold boot only: give the sense
* hardware time to settle, then force a fresh classification.
*/
static void alc_fixup_headset_mode_acer_coldboot(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
alc_fixup_headset_mode(codec, fix, action);
if (action == HDA_FIXUP_ACT_INIT &&
!is_s3_resume(codec) && !is_s4_resume(codec) &&
spec->current_headset_mode != ALC_HEADSET_MODE_UNPLUGGED) {
msleep(500);
spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
alc_fixup_headset_mode(codec, fix, action);
}
}
static void alc288_update_headset_jack_cb(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@ -4248,6 +4275,7 @@ enum {
ALC282_FIXUP_ACER_DISABLE_LINEOUT,
ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST,
ALC256_FIXUP_ACER_HEADSET_MIC,
ALC256_FIXUP_ACER_COLDBOOT,
ALC285_FIXUP_IDEAPAD_S740_COEF,
ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST,
ALC295_FIXUP_ASUS_DACS,
@ -6311,6 +6339,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
},
[ALC256_FIXUP_ACER_COLDBOOT] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_acer_coldboot,
.chained = true,
.chain_id = ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
},
[ALC285_FIXUP_IDEAPAD_S740_COEF] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_ideapad_s740_coef,
@ -7148,13 +7182,14 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x159e, "Acer Nitro 5 AN515-46", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_COLDBOOT),
SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x166c, "Acer Predator PH16-71", 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, 0x1731, "Acer Predator PHN16-72", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1758, "Acer Nitro ANV15-41", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
@ -8100,6 +8135,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x380b, "Lenovo Yoga Slim 9 14ILL10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
/* Yoga Pro 9 16IMH9 and Legion 7 16ITHG6 share PCI SSID 17aa:3811
* with Legion S7 15IMH05; use codec SSID to distinguish them
*/
@ -8287,6 +8323,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d05, 0x3034, "TongFang X6KK45xU", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d05, 0x30ba, "TongFang XxAF5xxx", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1d19, 0x0006, "VAIO VJS131", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),

View File

@ -404,6 +404,7 @@ static void setup_fg_nodes(struct hdac_device *codec)
*/
int snd_hdac_refresh_widgets(struct hdac_device *codec)
{
hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
hda_nid_t start_nid;
int nums, err = 0;
@ -412,10 +413,10 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec)
* widgets array.
*/
guard(mutex)(&codec->widget_lock);
nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
nums = snd_hdac_get_sub_nodes(codec, fg, &start_nid);
if (!start_nid || nums <= 0 || nums >= 0xff) {
dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n",
codec->afg);
fg);
return -EINVAL;
}

View File

@ -868,6 +868,9 @@ snd_harmony_create(struct snd_card *card,
goto free_and_ret;
}
spin_lock_init(&h->mixer_lock);
spin_lock_init(&h->lock);
err = request_irq(padev->irq, snd_harmony_interrupt, 0,
"harmony", h);
if (err) {
@ -877,9 +880,6 @@ snd_harmony_create(struct snd_card *card,
}
h->irq = padev->irq;
spin_lock_init(&h->mixer_lock);
spin_lock_init(&h->lock);
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, h, &ops);
if (err < 0)
goto free_and_ret;

View File

@ -828,16 +828,13 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
cdev->data_urbs_in = alloc_urbs(cdev, SNDRV_PCM_STREAM_CAPTURE, &ret);
if (ret < 0) {
kfree(cdev->data_cb_info);
free_urbs(cdev->data_urbs_in);
snd_usb_caiaq_audio_free(cdev);
return ret;
}
cdev->data_urbs_out = alloc_urbs(cdev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
if (ret < 0) {
kfree(cdev->data_cb_info);
free_urbs(cdev->data_urbs_in);
free_urbs(cdev->data_urbs_out);
snd_usb_caiaq_audio_free(cdev);
return ret;
}
@ -858,6 +855,9 @@ void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)
dev_dbg(dev, "%s(%p)\n", __func__, cdev);
free_urbs(cdev->data_urbs_in);
cdev->data_urbs_in = NULL;
free_urbs(cdev->data_urbs_out);
cdev->data_urbs_out = NULL;
kfree(cdev->data_cb_info);
cdev->data_cb_info = NULL;
}

View File

@ -191,6 +191,10 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode,
const int max_retries = 5;
int err;
CLASS(snd_usb_lock, pm)(mixer->chip);
if (pm.err < 0)
return -EIO;
if (!private->urb)
return -ENODEV;
@ -1026,6 +1030,10 @@ static int fcp_init(struct usb_mixer_interface *mixer,
struct usb_device *dev = mixer->chip->dev;
int err;
CLASS(snd_usb_lock, pm)(mixer->chip);
if (pm.err < 0)
return -EIO;
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
FCP_USB_REQ_STEP0,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,

View File

@ -971,6 +971,8 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
default:
count = 2;
}
if (ep->max_transfer < count)
return;
count = snd_rawmidi_transmit(ep->ports[0].substream,
urb->transfer_buffer,
count);

View File

@ -518,6 +518,19 @@ static const struct usbmix_name_map audient_id14_map[] = {
{}
};
/*
* Audient iD24: feature unit 12 ("Speaker Playback Volume") sits in the
* monitor-mixer branch and does not apply volume to all of its channels;
* when userspace adopts it as the master playback volume, the left main
* output stays at 0 dB while the right one is attenuated, producing a
* stereo imbalance. Rename it so that it is not picked up as the
* stream's master volume control.
*/
static const struct usbmix_name_map audient_id24_map[] = {
{ 12, "Monitor Mix Playback" }, /* FU, partial channel coverage */
{}
};
/*
* Control map entries
*/
@ -611,6 +624,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x2708, 0x0008),
.map = audient_id14_map,
},
{
/* Audient iD24 */
.id = USB_ID(0x2708, 0x000d),
.map = audient_id24_map,
},
{
/* KEF X300A */
.id = USB_ID(0x27ac, 0x1000),

View File

@ -3480,6 +3480,10 @@ static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u
struct usb_device *dev = chip->dev;
int err;
CLASS(snd_usb_lock, pm)(chip);
if (pm.err < 0)
return -EIO;
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
item,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
@ -3499,6 +3503,10 @@ static int snd_rme_digiface_read_status(struct snd_kcontrol *kcontrol, u32 statu
__le32 buf[4] = {};
int err;
CLASS(snd_usb_lock, pm)(chip);
if (pm.err < 0)
return -EIO;
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
RME_DIGIFACE_READ_STATUS,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,

View File

@ -474,6 +474,10 @@ snd_s1810c_switch_get(struct snd_kcontrol *kctl,
u32 state = 0;
int ret;
CLASS(snd_usb_lock, pm)(mixer->chip);
if (pm.err < 0)
return -EIO;
guard(mutex)(&private->data_mutex);
ret = snd_s1810c_get_switch_state(mixer, kctl, &state);
if (ret < 0)
@ -504,6 +508,10 @@ snd_s1810c_switch_set(struct snd_kcontrol *kctl,
u32 newval = 0;
int ret = 0;
CLASS(snd_usb_lock, pm)(mixer->chip);
if (pm.err < 0)
return -EIO;
guard(mutex)(&private->data_mutex);
ret = snd_s1810c_get_switch_state(mixer, kctl, &curval);
if (ret < 0)

View File

@ -707,6 +707,10 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
int err;
CLASS(snd_usb_lock, pm)(chip);
if (pm.err < 0)
return -EIO;
err = snd_usb_ctl_msg(chip->dev,
usb_rcvctrlpipe(chip->dev, 0),
UAC2_CS_MEM,

View File

@ -2603,9 +2603,9 @@ static int scarlett2_usb_rx(struct usb_device *dev, int interface,
}
/* Send a proprietary format request to the Scarlett interface */
static int scarlett2_usb(
struct usb_mixer_interface *mixer, u32 cmd,
void *req_data, u16 req_size, void *resp_data, u16 resp_size)
static int scarlett2_usb_nopm(struct usb_mixer_interface *mixer, u32 cmd,
void *req_data, u16 req_size,
void *resp_data, u16 resp_size)
{
struct scarlett2_data *private = mixer->private_data;
struct usb_device *dev = mixer->chip->dev;
@ -2713,6 +2713,18 @@ static int scarlett2_usb(
return err;
}
static int scarlett2_usb(struct usb_mixer_interface *mixer, u32 cmd,
void *req_data, u16 req_size,
void *resp_data, u16 resp_size)
{
CLASS(snd_usb_lock, pm)(mixer->chip);
if (pm.err < 0)
return -EIO;
return scarlett2_usb_nopm(mixer, cmd, req_data, req_size,
resp_data, resp_size);
}
/* Send a USB message to get data; result placed in *buf */
static int scarlett2_usb_get(
struct usb_mixer_interface *mixer,
@ -3020,9 +3032,21 @@ static int scarlett2_usb_set_config_buf(
/* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */
static void scarlett2_config_save(struct usb_mixer_interface *mixer)
{
int err;
__le32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE);
int err = scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD,
&req, sizeof(req), NULL, 0);
if (err < 0)
usb_audio_err(mixer->chip, "config save failed: %d\n", err);
}
/* The USB suspend callback must not acquire another PM reference. */
static void scarlett2_config_save_nopm(struct usb_mixer_interface *mixer)
{
__le32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE);
int err = scarlett2_usb_nopm(mixer, SCARLETT2_USB_DATA_CMD,
&req, sizeof(req), NULL, 0);
err = scarlett2_usb_activate_config(mixer, SCARLETT2_USB_CONFIG_SAVE);
if (err < 0)
usb_audio_err(mixer->chip, "config save failed: %d\n", err);
}
@ -8639,7 +8663,7 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
struct scarlett2_data *private = mixer->private_data;
if (cancel_delayed_work_sync(&private->work))
scarlett2_config_save(private->mixer);
scarlett2_config_save_nopm(private->mixer);
scarlett2_cleanup_urb(mixer);
}

View File

@ -151,6 +151,9 @@ static const char *const route_names[] = {
static int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
unsigned char *buf, int size)
{
CLASS(snd_usb_lock, pm)(chip);
if (pm.err < 0)
return -EIO;
guard(mutex)(&chip->mutex);
snd_usb_ctl_msg(chip->dev,
@ -165,6 +168,10 @@ static int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
*/
static int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
{
CLASS(snd_usb_lock, pm)(chip);
if (pm.err < 0)
return -EIO;
return snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE,
0, 0, buf, size);

View File

@ -319,8 +319,8 @@ static bool ctl_value_index_valid(struct ctl_data *ctl,
/* Only check step size if there is one and we're in bounds */
if (snd_ctl_elem_info_get_step(ctl->info) &&
(int_val - snd_ctl_elem_info_get_min(ctl->info) %
snd_ctl_elem_info_get_step(ctl->info))) {
(int_val - snd_ctl_elem_info_get_min(ctl->info)) %
snd_ctl_elem_info_get_step(ctl->info)) {
ksft_print_msg("%s.%d value %ld invalid for step %ld minimum %ld\n",
ctl->name, index, int_val,
snd_ctl_elem_info_get_step(ctl->info),