Commit b317b032 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 43a8e50a
...@@ -3240,102 +3240,8 @@ enum { ...@@ -3240,102 +3240,8 @@ enum {
CXT_FIXUP_THINKPAD_ACPI, CXT_FIXUP_THINKPAD_ACPI,
}; };
#if IS_ENABLED(CONFIG_THINKPAD_ACPI) /* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
#include <linux/thinkpad_acpi.h>
#include <linux/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 conexant_spec *spec = codec->spec;
if (spec->dynamic_eapd)
cx_auto_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_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 cxt_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct conexant_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->gen.vmaster_mute.hook = update_tpacpi_mute_led;
removefunc = false;
}
if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
if (spec->gen.num_adc_nids > 1)
snd_printdd("Skipping micmute LED control due to several ADCs");
else {
spec->gen.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
static void cxt_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
}
#endif
static void cxt_fixup_stereo_dmic(struct hda_codec *codec, static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action) const struct hda_fixup *fix, int action)
...@@ -3492,7 +3398,7 @@ static const struct hda_fixup cxt_fixups[] = { ...@@ -3492,7 +3398,7 @@ static const struct hda_fixup cxt_fixups[] = {
}, },
[CXT_FIXUP_THINKPAD_ACPI] = { [CXT_FIXUP_THINKPAD_ACPI] = {
.type = HDA_FIXUP_FUNC, .type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_thinkpad_acpi, .v.func = hda_fixup_thinkpad_acpi,
}, },
}; };
......
...@@ -3781,95 +3781,8 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec, ...@@ -3781,95 +3781,8 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec,
} }
} }
#if IS_ENABLED(CONFIG_THINKPAD_ACPI) /* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
#include <linux/thinkpad_acpi.h>
#include <linux/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)
{
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 alc_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_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->gen.vmaster_mute.hook = update_tpacpi_mute_led;
removefunc = false;
}
if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
if (spec->gen.num_adc_nids > 1)
snd_printdd("Skipping micmute LED control due to several ADCs");
else {
spec->gen.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
static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
}
#endif
enum { enum {
ALC269_FIXUP_SONY_VAIO, ALC269_FIXUP_SONY_VAIO,
...@@ -4273,7 +4186,7 @@ static const struct hda_fixup alc269_fixups[] = { ...@@ -4273,7 +4186,7 @@ static const struct hda_fixup alc269_fixups[] = {
}, },
[ALC269_FIXUP_THINKPAD_ACPI] = { [ALC269_FIXUP_THINKPAD_ACPI] = {
.type = HDA_FIXUP_FUNC, .type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_thinkpad_acpi, .v.func = hda_fixup_thinkpad_acpi,
}, },
[ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS, .type = HDA_FIXUP_PINS,
......
/* 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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment