Commit 34417833 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull sound fixes from Takashi Iwai:
 "No surprise here, only a collection of device-specific fixes for
  USB-audio and HD-audio at this time"

* tag 'sound-5.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda/hdmi: Cancel pending works before suspend
  ALSA: hda: Avoid spurious unsol event handling during S3/S4
  ALSA: hda: Flush pending unsolicited events before suspend
  ALSA: usb-audio: fix use after free in usb_audio_disconnect
  ALSA: usb-audio: fix NULL ptr dereference in usb_audio_probe
  ALSA: hda/ca0132: Add Sound BlasterX AE-5 Plus support
  ALSA: hda: Drop the BATCH workaround for AMD controllers
  ALSA: hda/conexant: Add quirk for mute LED control on HP ZBook G5
  ALSA: usb-audio: Apply the control quirk to Plantronics headsets
  ALSA: usb-audio: Fix "cannot get freq eq" errors on Dell AE515 sound bar
  ALSA: hda: ignore invalid NHLT table
  ALSA: usb-audio: Disable USB autosuspend properly in setup_disable_autosuspend()
  ALSA: usb: Add Plantronics C320-M USB ctrl msg delay quirk
parents 568099a7 eea46a08
...@@ -39,6 +39,11 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) ...@@ -39,6 +39,11 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
if (!nhlt) if (!nhlt)
return 0; return 0;
if (nhlt->header.length <= sizeof(struct acpi_table_header)) {
dev_warn(dev, "Invalid DMIC description table\n");
return 0;
}
for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++, for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++,
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) { epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) {
......
...@@ -47,6 +47,10 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) ...@@ -47,6 +47,10 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
if (codec->bus->shutdown) if (codec->bus->shutdown)
return; return;
/* ignore unsol events during system suspend/resume */
if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
return;
if (codec->patch_ops.unsol_event) if (codec->patch_ops.unsol_event)
codec->patch_ops.unsol_event(codec, ev); codec->patch_ops.unsol_event(codec, ev);
} }
......
...@@ -609,13 +609,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -609,13 +609,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
20, 20,
178000000); 178000000);
/* by some reason, the playback stream stalls on PulseAudio with
* tsched=1 when a capture stream triggers. Until we figure out the
* real cause, disable tsched mode by telling the PCM info flag.
*/
if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND)
runtime->hw.info |= SNDRV_PCM_INFO_BATCH;
if (chip->align_buffer_size) if (chip->align_buffer_size)
/* constrain buffer sizes to be multiple of 128 /* constrain buffer sizes to be multiple of 128
bytes. This is more efficient in terms of memory bytes. This is more efficient in terms of memory
......
...@@ -1026,6 +1026,8 @@ static int azx_prepare(struct device *dev) ...@@ -1026,6 +1026,8 @@ static int azx_prepare(struct device *dev)
chip = card->private_data; chip = card->private_data;
chip->pm_prepared = 1; chip->pm_prepared = 1;
flush_work(&azx_bus(chip)->unsol_work);
/* HDA controller always requires different WAKEEN for runtime suspend /* HDA controller always requires different WAKEEN for runtime suspend
* and system suspend, so don't use direct-complete here. * and system suspend, so don't use direct-complete here.
*/ */
......
...@@ -1309,6 +1309,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = { ...@@ -1309,6 +1309,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D), SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D), SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D),
SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5), SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
SND_PCI_QUIRK(0x1102, 0x0191, "Sound Blaster AE-5 Plus", QUIRK_AE5),
SND_PCI_QUIRK(0x1102, 0x0081, "Sound Blaster AE-7", QUIRK_AE7), SND_PCI_QUIRK(0x1102, 0x0081, "Sound Blaster AE-7", QUIRK_AE7),
{} {}
}; };
......
...@@ -149,6 +149,21 @@ static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev, ...@@ -149,6 +149,21 @@ static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
return 0; return 0;
} }
static void cxt_init_gpio_led(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
if (mask) {
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
mask);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
mask);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led);
}
}
static int cx_auto_init(struct hda_codec *codec) static int cx_auto_init(struct hda_codec *codec)
{ {
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
...@@ -156,6 +171,7 @@ static int cx_auto_init(struct hda_codec *codec) ...@@ -156,6 +171,7 @@ static int cx_auto_init(struct hda_codec *codec)
if (!spec->dynamic_eapd) if (!spec->dynamic_eapd)
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
cxt_init_gpio_led(codec);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
return 0; return 0;
...@@ -215,6 +231,7 @@ enum { ...@@ -215,6 +231,7 @@ enum {
CXT_FIXUP_HP_SPECTRE, CXT_FIXUP_HP_SPECTRE,
CXT_FIXUP_HP_GATE_MIC, CXT_FIXUP_HP_GATE_MIC,
CXT_FIXUP_MUTE_LED_GPIO, CXT_FIXUP_MUTE_LED_GPIO,
CXT_FIXUP_HP_ZBOOK_MUTE_LED,
CXT_FIXUP_HEADSET_MIC, CXT_FIXUP_HEADSET_MIC,
CXT_FIXUP_HP_MIC_NO_PRESENCE, CXT_FIXUP_HP_MIC_NO_PRESENCE,
}; };
...@@ -654,31 +671,36 @@ static int cxt_gpio_micmute_update(struct led_classdev *led_cdev, ...@@ -654,31 +671,36 @@ static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
return 0; return 0;
} }
static void cxt_setup_mute_led(struct hda_codec *codec,
static void cxt_fixup_mute_led_gpio(struct hda_codec *codec, unsigned int mute, unsigned int mic_mute)
const struct hda_fixup *fix, int action)
{ {
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
static const struct hda_verb gpio_init[] = {
{ 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
{}
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gpio_led = 0;
spec->mute_led_polarity = 0;
if (mute) {
snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update); snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
spec->gpio_led = 0; spec->gpio_mute_led_mask = mute;
spec->mute_led_polarity = 0; }
spec->gpio_mute_led_mask = 0x01; if (mic_mute) {
spec->gpio_mic_led_mask = 0x02;
snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update); snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
spec->gpio_mic_led_mask = mic_mute;
} }
snd_hda_add_verbs(codec, gpio_init);
if (spec->gpio_led)
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led);
} }
static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
if (action == HDA_FIXUP_ACT_PRE_PROBE)
cxt_setup_mute_led(codec, 0x01, 0x02);
}
static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
if (action == HDA_FIXUP_ACT_PRE_PROBE)
cxt_setup_mute_led(codec, 0x10, 0x20);
}
/* ThinkPad X200 & co with cxt5051 */ /* ThinkPad X200 & co with cxt5051 */
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
...@@ -839,6 +861,10 @@ static const struct hda_fixup cxt_fixups[] = { ...@@ -839,6 +861,10 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC, .type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_mute_led_gpio, .v.func = cxt_fixup_mute_led_gpio,
}, },
[CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_hp_zbook_mute_led,
},
[CXT_FIXUP_HEADSET_MIC] = { [CXT_FIXUP_HEADSET_MIC] = {
.type = HDA_FIXUP_FUNC, .type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_headset_mic, .v.func = cxt_fixup_headset_mic,
...@@ -917,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { ...@@ -917,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
...@@ -956,6 +983,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { ...@@ -956,6 +983,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" }, { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" }, { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
{ .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" }, { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
{ .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
{ .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" }, { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
{} {}
}; };
......
...@@ -2480,6 +2480,18 @@ static void generic_hdmi_free(struct hda_codec *codec) ...@@ -2480,6 +2480,18 @@ static void generic_hdmi_free(struct hda_codec *codec)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int generic_hdmi_suspend(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
cancel_delayed_work_sync(&per_pin->work);
}
return 0;
}
static int generic_hdmi_resume(struct hda_codec *codec) static int generic_hdmi_resume(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
...@@ -2503,6 +2515,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { ...@@ -2503,6 +2515,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
.build_controls = generic_hdmi_build_controls, .build_controls = generic_hdmi_build_controls,
.unsol_event = hdmi_unsol_event, .unsol_event = hdmi_unsol_event,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = generic_hdmi_suspend,
.resume = generic_hdmi_resume, .resume = generic_hdmi_resume,
#endif #endif
}; };
......
...@@ -830,6 +830,9 @@ static int usb_audio_probe(struct usb_interface *intf, ...@@ -830,6 +830,9 @@ static int usb_audio_probe(struct usb_interface *intf,
snd_media_device_create(chip, intf); snd_media_device_create(chip, intf);
} }
if (quirk)
chip->quirk_type = quirk->type;
usb_chip[chip->index] = chip; usb_chip[chip->index] = chip;
chip->intf[chip->num_interfaces] = intf; chip->intf[chip->num_interfaces] = intf;
chip->num_interfaces++; chip->num_interfaces++;
...@@ -904,6 +907,9 @@ static void usb_audio_disconnect(struct usb_interface *intf) ...@@ -904,6 +907,9 @@ static void usb_audio_disconnect(struct usb_interface *intf)
} }
} }
if (chip->quirk_type & QUIRK_SETUP_DISABLE_AUTOSUSPEND)
usb_enable_autosuspend(interface_to_usbdev(intf));
chip->num_interfaces--; chip->num_interfaces--;
if (chip->num_interfaces <= 0) { if (chip->num_interfaces <= 0) {
usb_chip[chip->index] = NULL; usb_chip[chip->index] = NULL;
......
...@@ -547,7 +547,7 @@ static int setup_disable_autosuspend(struct snd_usb_audio *chip, ...@@ -547,7 +547,7 @@ static int setup_disable_autosuspend(struct snd_usb_audio *chip,
struct usb_driver *driver, struct usb_driver *driver,
const struct snd_usb_audio_quirk *quirk) const struct snd_usb_audio_quirk *quirk)
{ {
driver->supports_autosuspend = 0; usb_disable_autosuspend(interface_to_usbdev(iface));
return 1; /* Continue with creating streams and mixer */ return 1; /* Continue with creating streams and mixer */
} }
...@@ -1520,6 +1520,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) ...@@ -1520,6 +1520,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */ case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */ case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */ case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
return true; return true;
} }
...@@ -1670,6 +1671,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, ...@@ -1670,6 +1671,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
&& (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
msleep(20); msleep(20);
/*
* Plantronics headsets (C320, C320-M, etc) need a delay to avoid
* random microhpone failures.
*/
if (USB_ID_VENDOR(chip->usb_id) == 0x047f &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
msleep(20);
/* Zoom R16/24, many Logitech(at least H650e/H570e/BCC950), /* Zoom R16/24, many Logitech(at least H650e/H570e/BCC950),
* Jabra 550a, Kingston HyperX needs a tiny delay here, * Jabra 550a, Kingston HyperX needs a tiny delay here,
* otherwise requests like get/set frequency return * otherwise requests like get/set frequency return
......
...@@ -27,6 +27,7 @@ struct snd_usb_audio { ...@@ -27,6 +27,7 @@ struct snd_usb_audio {
struct snd_card *card; struct snd_card *card;
struct usb_interface *intf[MAX_CARD_INTERFACES]; struct usb_interface *intf[MAX_CARD_INTERFACES];
u32 usb_id; u32 usb_id;
uint16_t quirk_type;
struct mutex mutex; struct mutex mutex;
unsigned int system_suspend; unsigned int system_suspend;
atomic_t active; atomic_t active;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment