Commit e65bf997 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Takashi Iwai
Browse files

ALSA: HDA - remove the custom implementation for the audio LED trigger



With the new snd-ctl-led module, we have a generic way
to trigger audio LEDs based on the sound control changes.

Remove the custom implementation from the HDA driver.

Move the LED initialization before snd_hda_gen_parse_auto_config()
call in all drivers to create marked controls there.

Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20210317172945.842280-5-perex@perex.cz


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 22d8de62
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -221,10 +221,8 @@ comment "Set to Y if you want auto-loading the codec driver"

config SND_HDA_GENERIC
	tristate "Enable generic HD-audio codec parser"
	select NEW_LEDS if SND_HDA_GENERIC_LEDS
	select SND_CTL_LED if SND_HDA_GENERIC_LEDS
	select LEDS_CLASS if SND_HDA_GENERIC_LEDS
	select LEDS_TRIGGERS if SND_HDA_GENERIC_LEDS
	select LEDS_TRIGGER_AUDIO if SND_HDA_GENERIC_LEDS
	help
	  Say Y or M here to enable the generic HD-audio codec parser
	  in snd-hda-intel driver.
+6 −63
Original line number Diff line number Diff line
@@ -1952,7 +1952,7 @@ static int add_follower(struct hda_codec *codec,
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
			  unsigned int *tlv, const char * const *followers,
			  const char *suffix, bool init_follower_vol,
			  struct snd_kcontrol **ctl_ret)
			  unsigned int access, struct snd_kcontrol **ctl_ret)
{
	struct snd_kcontrol *kctl;
	int err;
@@ -1968,6 +1968,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
	kctl = snd_ctl_make_virtual_master(name, tlv);
	if (!kctl)
		return -ENOMEM;
	kctl->vd[0].access |= access;
	err = snd_hda_ctl_add(codec, 0, kctl);
	if (err < 0)
		return err;
@@ -1994,87 +1995,29 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
}
EXPORT_SYMBOL_GPL(__snd_hda_add_vmaster);

/*
 * mute-LED control using vmaster
 */
static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_info *uinfo)
{
	static const char * const texts[] = {
		"On", "Off", "Follow Master"
	};

	return snd_ctl_enum_info(uinfo, 1, 3, texts);
}

static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
{
	struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
	ucontrol->value.enumerated.item[0] = hook->mute_mode;
	return 0;
}

static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
{
	struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
	unsigned int old_mode = hook->mute_mode;

	hook->mute_mode = ucontrol->value.enumerated.item[0];
	if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER)
		hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
	if (old_mode == hook->mute_mode)
		return 0;
	snd_hda_sync_vmaster_hook(hook);
	return 1;
}

static const struct snd_kcontrol_new vmaster_mute_mode = {
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "Mute-LED Mode",
	.info = vmaster_mute_mode_info,
	.get = vmaster_mute_mode_get,
	.put = vmaster_mute_mode_put,
};

/* meta hook to call each driver's vmaster hook */
static void vmaster_hook(void *private_data, int enabled)
{
	struct hda_vmaster_mute_hook *hook = private_data;

	if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER)
		enabled = hook->mute_mode;
	hook->hook(hook->codec, enabled);
}

/**
 * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED
 * snd_hda_add_vmaster_hook - Add a vmaster hw specific hook
 * @codec: the HDA codec
 * @hook: the vmaster hook object
 * @expose_enum_ctl: flag to create an enum ctl
 *
 * Add a mute-LED hook with the given vmaster switch kctl.
 * When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically
 * created and associated with the given hook.
 * Add a hw specific hook (like EAPD) with the given vmaster switch kctl.
 */
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
			     struct hda_vmaster_mute_hook *hook,
			     bool expose_enum_ctl)
			     struct hda_vmaster_mute_hook *hook)
{
	struct snd_kcontrol *kctl;

	if (!hook->hook || !hook->sw_kctl)
		return 0;
	hook->codec = codec;
	hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
	snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook);
	if (!expose_enum_ctl)
	return 0;
	kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
	if (!kctl)
		return -ENOMEM;
	return snd_hda_ctl_add(codec, 0, kctl);
}
EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);

+25 −137
Original line number Diff line number Diff line
@@ -981,6 +981,8 @@ add_control(struct hda_gen_spec *spec, int type, const char *name,
	knew->index = cidx;
	if (get_amp_nid_(val))
		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
	if (knew->access == 0)
		knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
	knew->private_value = val;
	return knew;
}
@@ -3618,8 +3620,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
			   amp_val_replace_channels(ctl, chs));
	if (!knew)
		return -ENOMEM;
	if (is_switch)
	if (is_switch) {
		knew->put = cap_single_sw_put;
		if (spec->mic_mute_led)
			knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
	}
	if (!inv_dmic)
		return 0;

@@ -3634,8 +3639,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
			   amp_val_replace_channels(ctl, 2));
	if (!knew)
		return -ENOMEM;
	if (is_switch)
	if (is_switch) {
		knew->put = cap_single_sw_put;
		if (spec->mic_mute_led)
			knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
	}
	return 0;
}

@@ -3676,6 +3684,8 @@ static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
		knew->index = idx;
		knew->private_value = sw_ctl;
		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
		if (spec->mic_mute_led)
			knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
	}
	return 0;
}
@@ -3917,11 +3927,6 @@ static int create_mute_led_cdev(struct hda_codec *codec,
	return devm_led_classdev_register(&codec->core.dev, cdev);
}

static void vmaster_update_mute_led(void *private_data, int enabled)
{
	ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
}

/**
 * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
 * @codec: the HDA codec
@@ -3945,134 +3950,11 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
	if (spec->vmaster_mute.hook)
		codec_err(codec, "vmaster hook already present before cdev!\n");

	spec->vmaster_mute.hook = vmaster_update_mute_led;
	spec->vmaster_mute_enum = 1;
	spec->vmaster_mute_led = 1;
	return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);

/*
 * mic mute LED hook helpers
 */
enum {
	MICMUTE_LED_ON,
	MICMUTE_LED_OFF,
	MICMUTE_LED_FOLLOW_CAPTURE,
	MICMUTE_LED_FOLLOW_MUTE,
};

static void call_micmute_led_update(struct hda_codec *codec)
{
	struct hda_gen_spec *spec = codec->spec;
	unsigned int val;

	switch (spec->micmute_led.led_mode) {
	case MICMUTE_LED_ON:
		val = 1;
		break;
	case MICMUTE_LED_OFF:
		val = 0;
		break;
	case MICMUTE_LED_FOLLOW_CAPTURE:
		val = !!spec->micmute_led.capture;
		break;
	case MICMUTE_LED_FOLLOW_MUTE:
	default:
		val = !spec->micmute_led.capture;
		break;
	}

	if (val == spec->micmute_led.led_value)
		return;
	spec->micmute_led.led_value = val;
	ledtrig_audio_set(LED_AUDIO_MICMUTE,
			  spec->micmute_led.led_value ? LED_ON : LED_OFF);
}

static void update_micmute_led(struct hda_codec *codec,
			       struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct hda_gen_spec *spec = codec->spec;
	unsigned int mask;

	if (spec->micmute_led.old_hook)
		spec->micmute_led.old_hook(codec, kcontrol, ucontrol);

	if (!ucontrol)
		return;
	mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
	if (!strcmp("Capture Switch", ucontrol->id.name)) {
		/* TODO: How do I verify if it's a mono or stereo here? */
		if (ucontrol->value.integer.value[0] ||
		    ucontrol->value.integer.value[1])
			spec->micmute_led.capture |= mask;
		else
			spec->micmute_led.capture &= ~mask;
		call_micmute_led_update(codec);
	}
}

static int micmute_led_mode_info(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_info *uinfo)
{
	static const char * const texts[] = {
		"On", "Off", "Follow Capture", "Follow Mute",
	};

	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}

static int micmute_led_mode_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct hda_gen_spec *spec = codec->spec;

	ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode;
	return 0;
}

static int micmute_led_mode_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct hda_gen_spec *spec = codec->spec;
	unsigned int mode;

	mode = ucontrol->value.enumerated.item[0];
	if (mode > MICMUTE_LED_FOLLOW_MUTE)
		mode = MICMUTE_LED_FOLLOW_MUTE;
	if (mode == spec->micmute_led.led_mode)
		return 0;
	spec->micmute_led.led_mode = mode;
	call_micmute_led_update(codec);
	return 1;
}

static const struct snd_kcontrol_new micmute_led_mode_ctl = {
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "Mic Mute-LED Mode",
	.info = micmute_led_mode_info,
	.get = micmute_led_mode_get,
	.put = micmute_led_mode_put,
};

/* Set up the capture sync hook for controlling the mic-mute LED */
static int add_micmute_led_hook(struct hda_codec *codec)
{
	struct hda_gen_spec *spec = codec->spec;

	spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
	spec->micmute_led.capture = 0;
	spec->micmute_led.led_value = -1;
	spec->micmute_led.old_hook = spec->cap_sync_hook;
	spec->cap_sync_hook = update_micmute_led;
	if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
		return -ENOMEM;
	return 0;
}

/**
 * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
 * @codec: the HDA codec
@@ -4091,6 +3973,7 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
				     int (*callback)(struct led_classdev *,
						     enum led_brightness))
{
	struct hda_gen_spec *spec = codec->spec;
	int err;

	if (callback) {
@@ -4101,7 +3984,8 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
		}
	}

	return add_micmute_led_hook(codec);
	spec->mic_mute_led = 1;
	return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
#endif /* CONFIG_SND_HDA_GENERIC_LEDS */
@@ -5060,6 +4944,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,

	parse_user_hints(codec);

	if (spec->vmaster_mute_led || spec->mic_mute_led)
		snd_ctl_led_request();

	if (spec->mixer_nid && !spec->mixer_merge_nid)
		spec->mixer_merge_nid = spec->mixer_nid;

@@ -5291,7 +5178,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
					  spec->vmaster_tlv, follower_pfxs,
					  "Playback Volume");
					  "Playback Volume", 0);
		if (err < 0)
			return err;
	}
@@ -5299,13 +5186,14 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
					    NULL, follower_pfxs,
					    "Playback Switch",
					    true, &spec->vmaster_mute.sw_kctl);
					    "Playback Switch", true,
					    spec->vmaster_mute_led ?
						SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
					    &spec->vmaster_mute.sw_kctl);
		if (err < 0)
			return err;
		if (spec->vmaster_mute.hook) {
			snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
						 spec->vmaster_mute_enum);
			snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
			snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
		}
	}
+2 −13
Original line number Diff line number Diff line
@@ -84,15 +84,6 @@ struct badness_table {
extern const struct badness_table hda_main_out_badness;
extern const struct badness_table hda_extra_out_badness;

struct hda_micmute_hook {
	unsigned int led_mode;
	unsigned int capture;
	unsigned int led_value;
	void (*old_hook)(struct hda_codec *codec,
			 struct snd_kcontrol *kcontrol,
			 struct snd_ctl_elem_value *ucontrol);
};

struct hda_gen_spec {
	char stream_name_analog[32];	/* analog PCM stream */
	const struct hda_pcm_stream *stream_analog_playback;
@@ -229,7 +220,8 @@ struct hda_gen_spec {
	unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
	unsigned int own_eapd_ctl:1; /* set EAPD by own function */
	unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */
	unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
	unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */
	unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */
	unsigned int indep_hp:1; /* independent HP supported */
	unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
	unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
@@ -285,9 +277,6 @@ struct hda_gen_spec {
			      struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol);

	/* mic mute LED hook; called via cap_sync_hook */
	struct hda_micmute_hook micmute_led;

	/* PCM hooks */
	void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
				  struct hda_codec *codec,
+4 −12
Original line number Diff line number Diff line
@@ -131,21 +131,15 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
			  unsigned int *tlv, const char * const *followers,
			  const char *suffix, bool init_follower_vol,
			  struct snd_kcontrol **ctl_ret);
#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix) \
	__snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, NULL)
			  unsigned int access, struct snd_kcontrol **ctl_ret);
#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \
	__snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL)
int snd_hda_codec_reset(struct hda_codec *codec);
void snd_hda_codec_register(struct hda_codec *codec);
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);

#define snd_hda_regmap_sync(codec)	snd_hdac_regmap_sync(&(codec)->core)

enum {
	HDA_VMUTE_OFF,
	HDA_VMUTE_ON,
	HDA_VMUTE_FOLLOW_MASTER,
};

struct hda_vmaster_mute_hook {
	/* below two fields must be filled by the caller of
	 * snd_hda_add_vmaster_hook() beforehand
@@ -153,13 +147,11 @@ struct hda_vmaster_mute_hook {
	struct snd_kcontrol *sw_kctl;
	void (*hook)(void *, int);
	/* below are initialized automatically */
	unsigned int mute_mode; /* HDA_VMUTE_XXX */
	struct hda_codec *codec;
};

int snd_hda_add_vmaster_hook(struct hda_codec *codec,
			     struct hda_vmaster_mute_hook *hook,
			     bool expose_enum_ctl);
			     struct hda_vmaster_mute_hook *hook);
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);

/* amp value bits */
Loading