Commit 3c0e1ed9 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'for-linus' into for-next



Pull 6.11-devel branch for further development.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents 8400291e 3c0b6f92
Loading
Loading
Loading
Loading
+23 −14
Original line number Diff line number Diff line
@@ -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;
			xbuf++;
			len--;
			if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
				status = UMP_SYSEX_STATUS_SINGLE;
			len--;
			offset++;
			xbuf++;
		}
		} 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;
}
+63 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+11 −45
Original line number Diff line number Diff line
@@ -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;
	}

+1 −0
Original line number Diff line number Diff line
@@ -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),