forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ALSA: hda - Split Thinkpad ACPI-related code
Both patch_realtek.c and patch_conexant.c contain the fairy same code snippet for supporting Thinkpad ACPI LED controls. Split them into thinkpad_helper.c and include it from both places. Although this isn't the best approach from the code size POV, the probability for coexistence of both Realtek and Conexant codecs on a single machine is pretty low, thus it'll end up with less memory footprint than splitting to yet another module. Signed-off-by: Takashi Iwai <[email protected]>
- Loading branch information
Showing
3 changed files
with
105 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* 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 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->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) | ||
{ | ||
struct hda_codec *codec = private_data; | ||
struct hda_gen_spec *spec = codec->spec; | ||
|
||
if (spec->vmaster_mute.hook) | ||
spec->vmaster_mute.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_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) { | ||
snd_printk(KERN_WARNING "Failed to find thinkpad-acpi symbol tpacpi_led_set\n"); | ||
return; | ||
} | ||
|
||
removefunc = true; | ||
if (led_set_func(TPACPI_LED_MUTE, false) >= 0) { | ||
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) | ||
snd_printdd("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; | ||
} | ||
} | ||
|
||
#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 */ |