Merge branch 'for-linus' into for-next

Pull 6.11-devel branch for further development.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2024-07-30 07:45:13 +02:00
commit 3c0e1ed9c8
5 changed files with 101 additions and 61 deletions

View File

@ -1192,44 +1192,53 @@ static int cvt_sysex_to_ump(struct snd_seq_client *dest,
{
struct snd_seq_ump_event ev_cvt;
unsigned char status;
u8 buf[6], *xbuf;
u8 buf[8], *xbuf;
int offset = 0;
int len, err;
bool finished = false;
if (!snd_seq_ev_is_variable(event))
return 0;
setup_ump_event(&ev_cvt, event);
for (;;) {
while (!finished) {
len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset);
if (len <= 0)
break;
if (WARN_ON(len > 6))
if (WARN_ON(len > sizeof(buf)))
break;
offset += len;
xbuf = buf;
status = UMP_SYSEX_STATUS_CONTINUE;
/* truncate the sysex start-marker */
if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) {
status = UMP_SYSEX_STATUS_START;
len--;
offset++;
xbuf++;
len--;
if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
status = UMP_SYSEX_STATUS_SINGLE;
len--;
}
} else {
if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
/* if the last of this packet or the 1st byte of the next packet
* is the end-marker, finish the transfer with this packet
*/
if (len > 0 && len < 8 &&
xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
if (status == UMP_SYSEX_STATUS_START)
status = UMP_SYSEX_STATUS_SINGLE;
else
status = UMP_SYSEX_STATUS_END;
len--;
} else {
status = UMP_SYSEX_STATUS_CONTINUE;
}
finished = true;
}
len = min(len, 6);
fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len);
err = __snd_seq_deliver_single_event(dest, dest_port,
(struct snd_seq_event *)&ev_cvt,
atomic, hop);
if (err < 0)
return err;
offset += len;
}
return 0;
}

View File

@ -4955,6 +4955,69 @@ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
}
EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
/* forcibly mute the speaker output without caching; return true if updated */
static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid)
{
if (!nid)
return false;
if (!nid_has_mute(codec, nid, HDA_OUTPUT))
return false; /* no mute, skip */
if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) &
HDA_AMP_MUTE)
return false; /* both channels already muted, skip */
/* direct amp update without caching */
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT |
AC_AMP_SET_RIGHT | HDA_AMP_MUTE);
return true;
}
/**
* snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs
* @codec: the HDA codec
*
* Forcibly mute the speaker outputs, to be called at suspend or shutdown.
*
* The mute state done by this function isn't cached, hence the original state
* will be restored at resume.
*
* Return true if the mute state has been changed.
*/
bool snd_hda_gen_shutup_speakers(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
const int *paths;
const struct nid_path *path;
int i, p, num_paths;
bool updated = false;
/* if already powered off, do nothing */
if (!snd_hdac_is_power_on(&codec->core))
return false;
if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
paths = spec->out_paths;
num_paths = spec->autocfg.line_outs;
} else {
paths = spec->speaker_paths;
num_paths = spec->autocfg.speaker_outs;
}
for (i = 0; i < num_paths; i++) {
path = snd_hda_get_path_from_idx(codec, paths[i]);
if (!path)
continue;
for (p = 0; p < path->depth; p++)
if (force_mute_output_path(codec, path->path[p]))
updated = true;
}
return updated;
}
EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers);
/**
* snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
* set up the hda_gen_spec

View File

@ -353,5 +353,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
int (*callback)(struct led_classdev *,
enum led_brightness));
bool snd_hda_gen_shutup_speakers(struct hda_codec *codec);
#endif /* __SOUND_HDA_GENERIC_H */

View File

@ -21,12 +21,6 @@
#include "hda_jack.h"
#include "hda_generic.h"
enum {
CX_HEADSET_NOPRESENT = 0,
CX_HEADSET_PARTPRESENT,
CX_HEADSET_ALLPRESENT,
};
struct conexant_spec {
struct hda_gen_spec gen;
@ -48,7 +42,6 @@ struct conexant_spec {
unsigned int gpio_led;
unsigned int gpio_mute_led_mask;
unsigned int gpio_mic_led_mask;
unsigned int headset_present_flag;
bool is_cx8070_sn6140;
};
@ -212,6 +205,8 @@ static void cx_auto_shutdown(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
snd_hda_gen_shutup_speakers(codec);
/* Turn the problematic codec into D3 to avoid spurious noises
from the internal speaker during (and after) reboot */
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
@ -250,48 +245,19 @@ static void cx_process_headset_plugin(struct hda_codec *codec)
}
}
static void cx_update_headset_mic_vref(struct hda_codec *codec, unsigned int res)
static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event)
{
unsigned int phone_present, mic_persent, phone_tag, mic_tag;
struct conexant_spec *spec = codec->spec;
unsigned int mic_present;
/* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled,
* the node 19 can only be config to microphone or disabled.
* Check hp&mic tag to process headset pulgin&plugout.
*/
phone_tag = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0);
mic_tag = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0);
if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT)) ||
(mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT))) {
phone_present = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_PIN_SENSE, 0x0);
if (!(phone_present & AC_PINSENSE_PRESENCE)) {/* headphone plugout */
spec->headset_present_flag = CX_HEADSET_NOPRESENT;
mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
return;
}
if (spec->headset_present_flag == CX_HEADSET_NOPRESENT) {
spec->headset_present_flag = CX_HEADSET_PARTPRESENT;
} else if (spec->headset_present_flag == CX_HEADSET_PARTPRESENT) {
mic_persent = snd_hda_codec_read(codec, 0x19, 0,
AC_VERB_GET_PIN_SENSE, 0x0);
/* headset is present */
if ((phone_present & AC_PINSENSE_PRESENCE) &&
(mic_persent & AC_PINSENSE_PRESENCE)) {
else
cx_process_headset_plugin(codec);
spec->headset_present_flag = CX_HEADSET_ALLPRESENT;
}
}
}
}
static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct conexant_spec *spec = codec->spec;
if (spec->is_cx8070_sn6140)
cx_update_headset_mic_vref(codec, res);
snd_hda_jack_unsol_event(codec, res);
}
static int cx_auto_suspend(struct hda_codec *codec)
@ -305,7 +271,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
.build_pcms = snd_hda_gen_build_pcms,
.init = cx_auto_init,
.free = cx_auto_free,
.unsol_event = cx_jack_unsol_event,
.unsol_event = snd_hda_jack_unsol_event,
.suspend = cx_auto_suspend,
.check_power_status = snd_hda_gen_check_power_status,
};
@ -1163,7 +1129,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
case 0x14f11f86:
case 0x14f11f87:
spec->is_cx8070_sn6140 = true;
spec->headset_present_flag = CX_HEADSET_NOPRESENT;
snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
break;
}

View File

@ -9872,6 +9872,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF),
SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK),
SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC),