geneve: avoid using stale geneve socket.
[cascardo/linux.git] / sound / pci / hda / thinkpad_helper.c
1 /* Helper functions for Thinkpad LED control;
2  * to be included from codec driver
3  */
4
5 #if IS_ENABLED(CONFIG_THINKPAD_ACPI)
6
7 #include <linux/acpi.h>
8 #include <linux/thinkpad_acpi.h>
9
10 static int (*led_set_func)(int, bool);
11 static void (*old_vmaster_hook)(void *, int);
12
13 static bool is_thinkpad(struct hda_codec *codec)
14 {
15         return (codec->core.subsystem_id >> 16 == 0x17aa) &&
16                (acpi_dev_found("LEN0068") || acpi_dev_found("IBM0068"));
17 }
18
19 static void update_tpacpi_mute_led(void *private_data, int enabled)
20 {
21         if (old_vmaster_hook)
22                 old_vmaster_hook(private_data, enabled);
23
24         if (led_set_func)
25                 led_set_func(TPACPI_LED_MUTE, !enabled);
26 }
27
28 static void update_tpacpi_micmute_led(struct hda_codec *codec,
29                                       struct snd_kcontrol *kcontrol,
30                                       struct snd_ctl_elem_value *ucontrol)
31 {
32         if (!ucontrol || !led_set_func)
33                 return;
34         if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
35                 /* TODO: How do I verify if it's a mono or stereo here? */
36                 bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
37                 led_set_func(TPACPI_LED_MICMUTE, !val);
38         }
39 }
40
41 static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
42                                     const struct hda_fixup *fix, int action)
43 {
44         struct hda_gen_spec *spec = codec->spec;
45         bool removefunc = false;
46
47         if (action == HDA_FIXUP_ACT_PROBE) {
48                 if (!is_thinkpad(codec))
49                         return;
50                 if (!led_set_func)
51                         led_set_func = symbol_request(tpacpi_led_set);
52                 if (!led_set_func) {
53                         codec_warn(codec,
54                                    "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
55                         return;
56                 }
57
58                 removefunc = true;
59                 if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
60                         old_vmaster_hook = spec->vmaster_mute.hook;
61                         spec->vmaster_mute.hook = update_tpacpi_mute_led;
62                         removefunc = false;
63                 }
64                 if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
65                         if (spec->num_adc_nids > 1)
66                                 codec_dbg(codec,
67                                           "Skipping micmute LED control due to several ADCs");
68                         else {
69                                 spec->cap_sync_hook = update_tpacpi_micmute_led;
70                                 removefunc = false;
71                         }
72                 }
73         }
74
75         if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
76                 symbol_put(tpacpi_led_set);
77                 led_set_func = NULL;
78                 old_vmaster_hook = NULL;
79         }
80 }
81
82 #else /* CONFIG_THINKPAD_ACPI */
83
84 static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
85                                     const struct hda_fixup *fix, int action)
86 {
87 }
88
89 #endif /* CONFIG_THINKPAD_ACPI */