hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/sound/pci/hda/hda_generic.c
....@@ -1,23 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Universal Interface for Intel High Definition Audio Codec
34 *
45 * Generic widget tree parser
56 *
67 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
7
- *
8
- * This driver is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
12
- *
13
- * This driver is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License
19
- * along with this program; if not, write to the Free Software
20
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
218 */
229
2310 #include <linux/init.h>
....@@ -29,10 +16,11 @@
2916 #include <linux/string.h>
3017 #include <linux/bitops.h>
3118 #include <linux/module.h>
19
+#include <linux/leds.h>
3220 #include <sound/core.h>
3321 #include <sound/jack.h>
3422 #include <sound/tlv.h>
35
-#include "hda_codec.h"
23
+#include <sound/hda_codec.h>
3624 #include "hda_local.h"
3725 #include "hda_auto_parser.h"
3826 #include "hda_jack.h"
....@@ -103,6 +91,12 @@
10391 free_kctls(spec);
10492 snd_array_free(&spec->paths);
10593 snd_array_free(&spec->loopback_list);
94
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
95
+ if (spec->led_cdevs[LED_AUDIO_MUTE])
96
+ led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
97
+ if (spec->led_cdevs[LED_AUDIO_MICMUTE])
98
+ led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
99
+#endif
106100 }
107101
108102 /*
....@@ -1159,8 +1153,8 @@
11591153 return path && path->ctls[ctl_type];
11601154 }
11611155
1162
-static const char * const channel_name[4] = {
1163
- "Front", "Surround", "CLFE", "Side"
1156
+static const char * const channel_name[] = {
1157
+ "Front", "Surround", "CLFE", "Side", "Back",
11641158 };
11651159
11661160 /* give some appropriate ctl name prefix for the given line out channel */
....@@ -1186,7 +1180,7 @@
11861180
11871181 /* multi-io channels */
11881182 if (ch >= cfg->line_outs)
1189
- return channel_name[ch];
1183
+ goto fixed_name;
11901184
11911185 switch (cfg->line_out_type) {
11921186 case AUTO_PIN_SPEAKER_OUT:
....@@ -1238,6 +1232,7 @@
12381232 if (cfg->line_outs == 1 && !spec->multi_ios)
12391233 return "Line Out";
12401234
1235
+ fixed_name:
12411236 if (ch >= ARRAY_SIZE(channel_name)) {
12421237 snd_BUG();
12431238 return "PCM";
....@@ -3913,6 +3908,73 @@
39133908 return 0;
39143909 }
39153910
3911
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
3912
+/*
3913
+ * vmaster mute LED hook helpers
3914
+ */
3915
+
3916
+static int create_mute_led_cdev(struct hda_codec *codec,
3917
+ int (*callback)(struct led_classdev *,
3918
+ enum led_brightness),
3919
+ bool micmute)
3920
+{
3921
+ struct hda_gen_spec *spec = codec->spec;
3922
+ struct led_classdev *cdev;
3923
+ int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
3924
+ int err;
3925
+
3926
+ cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
3927
+ if (!cdev)
3928
+ return -ENOMEM;
3929
+
3930
+ cdev->name = micmute ? "hda::micmute" : "hda::mute";
3931
+ cdev->max_brightness = 1;
3932
+ cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
3933
+ cdev->brightness_set_blocking = callback;
3934
+ cdev->brightness = ledtrig_audio_get(idx);
3935
+ cdev->flags = LED_CORE_SUSPENDRESUME;
3936
+
3937
+ err = led_classdev_register(&codec->core.dev, cdev);
3938
+ if (err < 0)
3939
+ return err;
3940
+ spec->led_cdevs[idx] = cdev;
3941
+ return 0;
3942
+}
3943
+
3944
+static void vmaster_update_mute_led(void *private_data, int enabled)
3945
+{
3946
+ ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
3947
+}
3948
+
3949
+/**
3950
+ * snd_dha_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
3951
+ * @codec: the HDA codec
3952
+ * @callback: the callback for LED classdev brightness_set_blocking
3953
+ */
3954
+int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
3955
+ int (*callback)(struct led_classdev *,
3956
+ enum led_brightness))
3957
+{
3958
+ struct hda_gen_spec *spec = codec->spec;
3959
+ int err;
3960
+
3961
+ if (callback) {
3962
+ err = create_mute_led_cdev(codec, callback, false);
3963
+ if (err) {
3964
+ codec_warn(codec, "failed to create a mute LED cdev\n");
3965
+ return err;
3966
+ }
3967
+ }
3968
+
3969
+ if (spec->vmaster_mute.hook)
3970
+ codec_err(codec, "vmaster hook already present before cdev!\n");
3971
+
3972
+ spec->vmaster_mute.hook = vmaster_update_mute_led;
3973
+ spec->vmaster_mute_enum = 1;
3974
+ return 0;
3975
+}
3976
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
3977
+
39163978 /*
39173979 * mic mute LED hook helpers
39183980 */
....@@ -3947,8 +4009,8 @@
39474009 if (val == spec->micmute_led.led_value)
39484010 return;
39494011 spec->micmute_led.led_value = val;
3950
- if (spec->micmute_led.update)
3951
- spec->micmute_led.update(codec);
4012
+ ledtrig_audio_set(LED_AUDIO_MICMUTE,
4013
+ spec->micmute_led.led_value ? LED_ON : LED_OFF);
39524014 }
39534015
39544016 static void update_micmute_led(struct hda_codec *codec,
....@@ -4020,20 +4082,8 @@
40204082 .put = micmute_led_mode_put,
40214083 };
40224084
4023
-/**
4024
- * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook
4025
- * @codec: the HDA codec
4026
- * @hook: the callback for updating LED
4027
- *
4028
- * Called from the codec drivers for offering the mic mute LED controls.
4029
- * When established, it sets up cap_sync_hook and triggers the callback at
4030
- * each time when the capture mixer switch changes. The callback is supposed
4031
- * to update the LED accordingly.
4032
- *
4033
- * Returns 0 if the hook is established or a negative error code.
4034
- */
4035
-int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
4036
- void (*hook)(struct hda_codec *))
4085
+/* Set up the capture sync hook for controlling the mic-mute LED */
4086
+static int add_micmute_led_hook(struct hda_codec *codec)
40374087 {
40384088 struct hda_gen_spec *spec = codec->spec;
40394089
....@@ -4041,13 +4091,44 @@
40414091 spec->micmute_led.capture = 0;
40424092 spec->micmute_led.led_value = -1;
40434093 spec->micmute_led.old_hook = spec->cap_sync_hook;
4044
- spec->micmute_led.update = hook;
40454094 spec->cap_sync_hook = update_micmute_led;
40464095 if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
40474096 return -ENOMEM;
40484097 return 0;
40494098 }
4050
-EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
4099
+
4100
+/**
4101
+ * snd_dha_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
4102
+ * @codec: the HDA codec
4103
+ * @callback: the callback for LED classdev brightness_set_blocking
4104
+ *
4105
+ * Called from the codec drivers for offering the mic mute LED controls.
4106
+ * This creates a LED classdev and sets up the cap_sync_hook that is called at
4107
+ * each time when the capture mixer switch changes.
4108
+ *
4109
+ * When NULL is passed to @callback, no classdev is created but only the
4110
+ * LED-trigger is set up.
4111
+ *
4112
+ * Returns 0 or a negative error.
4113
+ */
4114
+int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
4115
+ int (*callback)(struct led_classdev *,
4116
+ enum led_brightness))
4117
+{
4118
+ int err;
4119
+
4120
+ if (callback) {
4121
+ err = create_mute_led_cdev(codec, callback, true);
4122
+ if (err) {
4123
+ codec_warn(codec, "failed to create a mic-mute LED cdev\n");
4124
+ return err;
4125
+ }
4126
+ }
4127
+
4128
+ return add_micmute_led_hook(codec);
4129
+}
4130
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
4131
+#endif /* CONFIG_SND_HDA_GENERIC_LEDS */
40514132
40524133 /*
40534134 * parse digital I/Os and set up NIDs in BIOS auto-parse mode
....@@ -4059,7 +4140,7 @@
40594140 int i, nums;
40604141 hda_nid_t dig_nid, pin;
40614142
4062
- /* support multiple SPDIFs; the secondary is set up as a slave */
4143
+ /* support multiple SPDIFs; the secondary is set up as a follower */
40634144 nums = 0;
40644145 for (i = 0; i < spec->autocfg.dig_outs; i++) {
40654146 pin = spec->autocfg.dig_out_pins[i];
....@@ -4078,10 +4159,10 @@
40784159 spec->multiout.dig_out_nid = dig_nid;
40794160 spec->dig_out_type = spec->autocfg.dig_out_type[0];
40804161 } else {
4081
- spec->multiout.slave_dig_outs = spec->slave_dig_outs;
4082
- if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
4162
+ spec->multiout.follower_dig_outs = spec->follower_dig_outs;
4163
+ if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1)
40834164 break;
4084
- spec->slave_dig_outs[nums - 1] = dig_nid;
4165
+ spec->follower_dig_outs[nums - 1] = dig_nid;
40854166 }
40864167 nums++;
40874168 }
....@@ -4397,7 +4478,7 @@
43974478 */
43984479
43994480 /* check each pin in the given array; returns true if any of them is plugged */
4400
-static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
4481
+static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins)
44014482 {
44024483 int i;
44034484 bool present = false;
....@@ -4416,7 +4497,7 @@
44164497 }
44174498
44184499 /* standard HP/line-out auto-mute helper */
4419
-static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
4500
+static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins,
44204501 int *paths, bool mute)
44214502 {
44224503 struct hda_gen_spec *spec = codec->spec;
....@@ -4536,7 +4617,7 @@
45364617 else
45374618 snd_hda_gen_update_outputs(codec);
45384619
4539
- /* sync the whole vmaster slaves to reflect the new auto-mute status */
4620
+ /* sync the whole vmaster followers to reflect the new auto-mute status */
45404621 if (spec->auto_mute_via_amp && !codec->bus->shutdown)
45414622 snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
45424623 }
....@@ -5180,8 +5261,8 @@
51805261 * Build control elements
51815262 */
51825263
5183
-/* slave controls for virtual master */
5184
-static const char * const slave_pfxs[] = {
5264
+/* follower controls for virtual master */
5265
+static const char * const follower_pfxs[] = {
51855266 "Front", "Surround", "Center", "LFE", "Side",
51865267 "Headphone", "Speaker", "Mono", "Line Out",
51875268 "CLFE", "Bass Speaker", "PCM",
....@@ -5233,7 +5314,7 @@
52335314 if (!spec->no_analog && !spec->suppress_vmaster &&
52345315 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
52355316 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
5236
- spec->vmaster_tlv, slave_pfxs,
5317
+ spec->vmaster_tlv, follower_pfxs,
52375318 "Playback Volume");
52385319 if (err < 0)
52395320 return err;
....@@ -5241,7 +5322,7 @@
52415322 if (!spec->no_analog && !spec->suppress_vmaster &&
52425323 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
52435324 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
5244
- NULL, slave_pfxs,
5325
+ NULL, follower_pfxs,
52455326 "Playback Switch",
52465327 true, &spec->vmaster_mute.sw_kctl);
52475328 if (err < 0)
....@@ -5756,7 +5837,7 @@
57565837 spec->stream_name_digital);
57575838 if (!info)
57585839 return -ENOMEM;
5759
- codec->slave_dig_outs = spec->multiout.slave_dig_outs;
5840
+ codec->follower_dig_outs = spec->multiout.follower_dig_outs;
57605841 spec->pcm_rec[1] = info;
57615842 if (spec->dig_out_type)
57625843 info->pcm_type = spec->dig_out_type;
....@@ -6023,7 +6104,7 @@
60236104 /* call init functions of standard auto-mute helpers */
60246105 update_automute_all(codec);
60256106
6026
- regcache_sync(codec->core.regmap);
6107
+ snd_hda_regmap_sync(codec);
60276108
60286109 if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
60296110 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);