![Takashi Iwai](/assets/img/avatar_default.png)
This reverts commit 7290006d8c
.
Through the regression report, it was revealed that the
tpacpi_led_set() call to thinkpad_acpi helper doesn't only toggle the
mute LED but actually mutes the sound. This is contradiction to the
expectation, and rather confuses user.
According to Henrique, it's not trivial to judge which TP model
behaves "LED-only" and which model does whatever more intrusive, as
Lenovo's implementations vary model by model. So, from the safety
reason, we should revert the patch for now.
Reported-by: Martin Steigerwald <martin@lichtvoll.de>
Cc: Pali Rohár <pali.rohar@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
103 lines
2.6 KiB
C
103 lines
2.6 KiB
C
/* 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 acpi_status acpi_check_cb(acpi_handle handle, u32 lvl, void *context,
|
|
void **rv)
|
|
{
|
|
bool *found = context;
|
|
*found = true;
|
|
return AE_OK;
|
|
}
|
|
|
|
static bool is_thinkpad(struct hda_codec *codec)
|
|
{
|
|
bool found = false;
|
|
if (codec->core.subsystem_id >> 16 != 0x17aa)
|
|
return false;
|
|
if (ACPI_SUCCESS(acpi_get_devices("LEN0068", acpi_check_cb, &found, NULL)) && found)
|
|
return true;
|
|
found = false;
|
|
return ACPI_SUCCESS(acpi_get_devices("IBM0068", acpi_check_cb, &found, NULL)) && found;
|
|
}
|
|
|
|
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_led(struct hda_codec *codec,
|
|
struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
if (!ucontrol || !led_set_func)
|
|
return;
|
|
if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
|
|
/* TODO: How do I verify if it's a mono or stereo here? */
|
|
bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
|
|
led_set_func(TPACPI_LED_MICMUTE, !val);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
if (spec->num_adc_nids > 1)
|
|
codec_dbg(codec,
|
|
"Skipping micmute LED control due to several ADCs");
|
|
else {
|
|
spec->cap_sync_hook = update_tpacpi_micmute_led;
|
|
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 */
|