Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d4e9bb3 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Add digital beep playback switch for STAC/IDT codecs

The digital beep widget may have no mute control, and always enabling
the beep is ofen pretty annoying, especially on laptops.

This patch adds a mixer control "PC Beep Playback Switch" when there
is no mixer amp mute is found, and controls it on software.

Reference: Novell bnc#444572
	https://bugzilla.novell.com/show_bug.cgi?id=444572



Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d7a89436
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@ static void snd_hda_generate_beep(struct work_struct *work)
		container_of(work, struct hda_beep, beep_work);
	struct hda_codec *codec = beep->codec;

	if (!beep->enabled)
		return;

	/* generate tone */
	snd_hda_codec_write_cache(codec, beep->nid, 0,
			AC_VERB_SET_BEEP_CONTROL, beep->tone);
@@ -115,6 +118,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
	beep->nid = nid;
	beep->dev = input_dev;
	beep->codec = codec;
	beep->enabled = 1;
	codec->beep = beep;

	INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ struct hda_beep {
	char phys[32];
	int tone;
	int nid;
	int enabled;
	struct work_struct beep_work; /* scheduled task for beep event */
};

+63 −6
Original line number Diff line number Diff line
@@ -2587,8 +2587,10 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
};

/* add dynamic controls */
static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
		int idx, const char *name, unsigned long val)
static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
				     struct snd_kcontrol_new *ktemp,
				     int idx, const char *name,
				     unsigned long val)
{
	struct snd_kcontrol_new *knew;

@@ -2607,7 +2609,7 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
	}

	knew = &spec->kctl_alloc[spec->num_kctl_used];
	*knew = stac92xx_control_templates[type];
	*knew = *ktemp;
	knew->index = idx;
	knew->name = kstrdup(name, GFP_KERNEL);
	if (!knew->name)
@@ -2617,9 +2619,18 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
	return 0;
}

static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
					   int type, int idx, const char *name,
					   unsigned long val)
{
	return stac92xx_add_control_temp(spec,
					 &stac92xx_control_templates[type],
					 idx, name, val);
}


/* add dynamic controls */
static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
				       const char *name, unsigned long val)
{
	return stac92xx_add_control_idx(spec, type, 0, name, val);
@@ -3062,6 +3073,43 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
	return 0;
}

#ifdef CONFIG_SND_HDA_INPUT_BEEP
#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info

static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_value *ucontrol)
{
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	ucontrol->value.integer.value[0] = codec->beep->enabled;
	return 0;
}

static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_value *ucontrol)
{
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	int enabled = !!ucontrol->value.integer.value[0];
	if (codec->beep->enabled != enabled) {
		codec->beep->enabled = enabled;
		return 1;
	}
	return 0;
}

static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.info = stac92xx_dig_beep_switch_info,
	.get = stac92xx_dig_beep_switch_get,
	.put = stac92xx_dig_beep_switch_put,
};

static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
{
	return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
					 0, "PC Beep Playback Switch", 0);
}
#endif

static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
{
	struct sigmatel_spec *spec = codec->spec;
@@ -3368,6 +3416,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
#ifdef CONFIG_SND_HDA_INPUT_BEEP
	if (spec->digbeep_nid > 0) {
		hda_nid_t nid = spec->digbeep_nid;
		unsigned int caps;

		err = stac92xx_auto_create_beep_ctls(codec, nid);
		if (err < 0)
@@ -3375,6 +3424,14 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
		err = snd_hda_attach_beep_device(codec, nid);
		if (err < 0)
			return err;
		/* if no beep switch is available, make its own one */
		caps = query_amp_caps(codec, nid, HDA_OUTPUT);
		if (codec->beep &&
		    !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
			err = stac92xx_beep_switch_ctl(codec);
			if (err < 0)
				return err;
		}
	}
#endif