|
@@ -2450,6 +2450,100 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
|
|
}
|
|
|
EXPORT_SYMBOL_HDA(__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[] = {
|
|
|
+ "Off", "On", "Follow Master"
|
|
|
+ };
|
|
|
+ unsigned int index;
|
|
|
+
|
|
|
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
|
|
+ uinfo->count = 1;
|
|
|
+ uinfo->value.enumerated.items = 3;
|
|
|
+ index = uinfo->value.enumerated.item;
|
|
|
+ if (index >= 3)
|
|
|
+ index = 2;
|
|
|
+ strcpy(uinfo->value.enumerated.name, texts[index]);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+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 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,
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * Add a mute-LED hook with the given vmaster switch kctl
|
|
|
+ * "Mute-LED Mode" control is automatically created and associated with
|
|
|
+ * the given hook.
|
|
|
+ */
|
|
|
+int snd_hda_add_vmaster_hook(struct hda_codec *codec,
|
|
|
+ struct hda_vmaster_mute_hook *hook)
|
|
|
+{
|
|
|
+ struct snd_kcontrol *kctl;
|
|
|
+
|
|
|
+ if (!hook->hook || !hook->sw_kctl)
|
|
|
+ return 0;
|
|
|
+ snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec);
|
|
|
+ hook->codec = codec;
|
|
|
+ hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
|
|
|
+ kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
|
|
|
+ if (!kctl)
|
|
|
+ return -ENOMEM;
|
|
|
+ return snd_hda_ctl_add(codec, 0, kctl);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Call the hook with the current value for synchronization
|
|
|
+ * Should be called in init callback
|
|
|
+ */
|
|
|
+void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
|
|
|
+{
|
|
|
+ if (!hook->hook || !hook->codec)
|
|
|
+ return;
|
|
|
+ switch (hook->mute_mode) {
|
|
|
+ case HDA_VMUTE_FOLLOW_MASTER:
|
|
|
+ snd_ctl_sync_vmaster_hook(hook->sw_kctl);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ hook->hook(hook->codec, hook->mute_mode);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook);
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
|
|
|
*
|