linux/sound/pci/hda/thinkpad_helper.c
Takashi Iwai 69b2c6d7c0 ALSA: hda - Use the common helper for thinkpad_acpi mic mute LED handling
Use the new common helper for setting up and controlling the mic mute
LED over thinkpad_acpi.  This also provides a new mixer enum "Mic
Mute-LED Mode" (that was present only for Dell models), which allows
user to choose the mic mute LED behavior.  For example, if you want
the mic mute LED turned on only while mic is on, choose "Follow
Capture" there.

Tested-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-06-21 13:52:24 +02:00

81 lines
2.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Helper functions for Thinkpad LED control;
* to be included from codec driver
*/
#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
#include <linux/acpi.h>
#include <linux/thinkpad_acpi.h>
static int (*led_set_func)(int, bool);
static void (*old_vmaster_hook)(void *, int);
static bool is_thinkpad(struct hda_codec *codec)
{
return (codec->core.subsystem_id >> 16 == 0x17aa) &&
(acpi_dev_found("LEN0068") || acpi_dev_found("LEN0268") ||
acpi_dev_found("IBM0068"));
}
static void update_tpacpi_mute_led(void *private_data, int enabled)
{
if (old_vmaster_hook)
old_vmaster_hook(private_data, enabled);
if (led_set_func)
led_set_func(TPACPI_LED_MUTE, !enabled);
}
static void update_tpacpi_micmute(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
}
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct hda_gen_spec *spec = codec->spec;
bool removefunc = false;
if (action == HDA_FIXUP_ACT_PROBE) {
if (!is_thinkpad(codec))
return;
if (!led_set_func)
led_set_func = symbol_request(tpacpi_led_set);
if (!led_set_func) {
codec_warn(codec,
"Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
return;
}
removefunc = true;
if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
old_vmaster_hook = spec->vmaster_mute.hook;
spec->vmaster_mute.hook = update_tpacpi_mute_led;
removefunc = false;
}
if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
snd_hda_gen_add_micmute_led(codec,
update_tpacpi_micmute) > 0)
removefunc = false;
}
if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
symbol_put(tpacpi_led_set);
led_set_func = NULL;
old_vmaster_hook = NULL;
}
}
#else /* CONFIG_THINKPAD_ACPI */
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
}
#endif /* CONFIG_THINKPAD_ACPI */