363 lines
14 KiB
Diff
363 lines
14 KiB
Diff
diff --git a/sound/hda/codecs/cirrus/cs420x.c b/sound/hda/codecs/cirrus/cs420x.c
|
|
--- a/sound/hda/codecs/cirrus/cs420x.c
|
|
+++ b/sound/hda/codecs/cirrus/cs420x.c
|
|
@@ -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 */
|
|
};
|
|
|
|
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
|
|
--- a/sound/hda/codecs/conexant.c
|
|
+++ b/sound/hda/codecs/conexant.c
|
|
@@ -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,
|
|
};
|
|
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
|
|
--- a/sound/hda/codecs/realtek/alc269.c
|
|
+++ b/sound/hda/codecs/realtek/alc269.c
|
|
@@ -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),
|
|
diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c
|
|
--- a/sound/usb/fcp.c
|
|
+++ b/sound/usb/fcp.c
|
|
@@ -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,
|
|
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
|
|
--- a/sound/usb/mixer_maps.c
|
|
+++ b/sound/usb/mixer_maps.c
|
|
@@ -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),
|
|
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
|
|
--- a/sound/usb/mixer_quirks.c
|
|
+++ b/sound/usb/mixer_quirks.c
|
|
@@ -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,
|
|
diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c
|
|
--- a/sound/usb/mixer_s1810c.c
|
|
+++ b/sound/usb/mixer_s1810c.c
|
|
@@ -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)
|
|
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
|
|
--- a/sound/usb/mixer_scarlett.c
|
|
+++ b/sound/usb/mixer_scarlett.c
|
|
@@ -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,
|
|
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
|
|
--- a/sound/usb/mixer_scarlett2.c
|
|
+++ b/sound/usb/mixer_scarlett2.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
|
|
--- a/sound/usb/mixer_us16x08.c
|
|
+++ b/sound/usb/mixer_us16x08.c
|
|
@@ -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);
|