mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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:
commit
3c0e1ed9c8
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user