From cf4ce59b3b70238352c7f1729f0f7223214828ad Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 20 Sep 2024 01:46:19 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux add concurrent mode --- kernel/sound/pci/hda/hda_generic.c | 179 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 130 insertions(+), 49 deletions(-) diff --git a/kernel/sound/pci/hda/hda_generic.c b/kernel/sound/pci/hda/hda_generic.c index ff263ad..35113fa 100644 --- a/kernel/sound/pci/hda/hda_generic.c +++ b/kernel/sound/pci/hda/hda_generic.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Universal Interface for Intel High Definition Audio Codec * * Generic widget tree parser * * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h> @@ -29,10 +16,11 @@ #include <linux/string.h> #include <linux/bitops.h> #include <linux/module.h> +#include <linux/leds.h> #include <sound/core.h> #include <sound/jack.h> #include <sound/tlv.h> -#include "hda_codec.h" +#include <sound/hda_codec.h> #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" @@ -103,6 +91,12 @@ free_kctls(spec); snd_array_free(&spec->paths); snd_array_free(&spec->loopback_list); +#ifdef CONFIG_SND_HDA_GENERIC_LEDS + if (spec->led_cdevs[LED_AUDIO_MUTE]) + led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]); + if (spec->led_cdevs[LED_AUDIO_MICMUTE]) + led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]); +#endif } /* @@ -1159,8 +1153,8 @@ return path && path->ctls[ctl_type]; } -static const char * const channel_name[4] = { - "Front", "Surround", "CLFE", "Side" +static const char * const channel_name[] = { + "Front", "Surround", "CLFE", "Side", "Back", }; /* give some appropriate ctl name prefix for the given line out channel */ @@ -1186,7 +1180,7 @@ /* multi-io channels */ if (ch >= cfg->line_outs) - return channel_name[ch]; + goto fixed_name; switch (cfg->line_out_type) { case AUTO_PIN_SPEAKER_OUT: @@ -1238,6 +1232,7 @@ if (cfg->line_outs == 1 && !spec->multi_ios) return "Line Out"; + fixed_name: if (ch >= ARRAY_SIZE(channel_name)) { snd_BUG(); return "PCM"; @@ -3913,6 +3908,73 @@ return 0; } +#ifdef CONFIG_SND_HDA_GENERIC_LEDS +/* + * vmaster mute LED hook helpers + */ + +static int create_mute_led_cdev(struct hda_codec *codec, + int (*callback)(struct led_classdev *, + enum led_brightness), + bool micmute) +{ + struct hda_gen_spec *spec = codec->spec; + struct led_classdev *cdev; + int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE; + int err; + + cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->name = micmute ? "hda::micmute" : "hda::mute"; + cdev->max_brightness = 1; + cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute"; + cdev->brightness_set_blocking = callback; + cdev->brightness = ledtrig_audio_get(idx); + cdev->flags = LED_CORE_SUSPENDRESUME; + + err = led_classdev_register(&codec->core.dev, cdev); + if (err < 0) + return err; + spec->led_cdevs[idx] = cdev; + return 0; +} + +static void vmaster_update_mute_led(void *private_data, int enabled) +{ + ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON); +} + +/** + * snd_dha_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED + * @codec: the HDA codec + * @callback: the callback for LED classdev brightness_set_blocking + */ +int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, + int (*callback)(struct led_classdev *, + enum led_brightness)) +{ + struct hda_gen_spec *spec = codec->spec; + int err; + + if (callback) { + err = create_mute_led_cdev(codec, callback, false); + if (err) { + codec_warn(codec, "failed to create a mute LED cdev\n"); + return err; + } + } + + if (spec->vmaster_mute.hook) + codec_err(codec, "vmaster hook already present before cdev!\n"); + + spec->vmaster_mute.hook = vmaster_update_mute_led; + spec->vmaster_mute_enum = 1; + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev); + /* * mic mute LED hook helpers */ @@ -3947,8 +4009,8 @@ if (val == spec->micmute_led.led_value) return; spec->micmute_led.led_value = val; - if (spec->micmute_led.update) - spec->micmute_led.update(codec); + ledtrig_audio_set(LED_AUDIO_MICMUTE, + spec->micmute_led.led_value ? LED_ON : LED_OFF); } static void update_micmute_led(struct hda_codec *codec, @@ -4020,20 +4082,8 @@ .put = micmute_led_mode_put, }; -/** - * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook - * @codec: the HDA codec - * @hook: the callback for updating LED - * - * Called from the codec drivers for offering the mic mute LED controls. - * When established, it sets up cap_sync_hook and triggers the callback at - * each time when the capture mixer switch changes. The callback is supposed - * to update the LED accordingly. - * - * Returns 0 if the hook is established or a negative error code. - */ -int snd_hda_gen_add_micmute_led(struct hda_codec *codec, - void (*hook)(struct hda_codec *)) +/* Set up the capture sync hook for controlling the mic-mute LED */ +static int add_micmute_led_hook(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; @@ -4041,13 +4091,44 @@ spec->micmute_led.capture = 0; spec->micmute_led.led_value = -1; spec->micmute_led.old_hook = spec->cap_sync_hook; - spec->micmute_led.update = hook; spec->cap_sync_hook = update_micmute_led; if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl)) return -ENOMEM; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led); + +/** + * snd_dha_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED + * @codec: the HDA codec + * @callback: the callback for LED classdev brightness_set_blocking + * + * Called from the codec drivers for offering the mic mute LED controls. + * This creates a LED classdev and sets up the cap_sync_hook that is called at + * each time when the capture mixer switch changes. + * + * When NULL is passed to @callback, no classdev is created but only the + * LED-trigger is set up. + * + * Returns 0 or a negative error. + */ +int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, + int (*callback)(struct led_classdev *, + enum led_brightness)) +{ + int err; + + if (callback) { + err = create_mute_led_cdev(codec, callback, true); + if (err) { + codec_warn(codec, "failed to create a mic-mute LED cdev\n"); + return err; + } + } + + return add_micmute_led_hook(codec); +} +EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev); +#endif /* CONFIG_SND_HDA_GENERIC_LEDS */ /* * parse digital I/Os and set up NIDs in BIOS auto-parse mode @@ -4059,7 +4140,7 @@ int i, nums; hda_nid_t dig_nid, pin; - /* support multiple SPDIFs; the secondary is set up as a slave */ + /* support multiple SPDIFs; the secondary is set up as a follower */ nums = 0; for (i = 0; i < spec->autocfg.dig_outs; i++) { pin = spec->autocfg.dig_out_pins[i]; @@ -4078,10 +4159,10 @@ spec->multiout.dig_out_nid = dig_nid; spec->dig_out_type = spec->autocfg.dig_out_type[0]; } else { - spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + spec->multiout.follower_dig_outs = spec->follower_dig_outs; + if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1) break; - spec->slave_dig_outs[nums - 1] = dig_nid; + spec->follower_dig_outs[nums - 1] = dig_nid; } nums++; } @@ -4397,7 +4478,7 @@ */ /* check each pin in the given array; returns true if any of them is plugged */ -static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins) { int i; bool present = false; @@ -4416,7 +4497,7 @@ } /* standard HP/line-out auto-mute helper */ -static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, +static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins, int *paths, bool mute) { struct hda_gen_spec *spec = codec->spec; @@ -4536,7 +4617,7 @@ else snd_hda_gen_update_outputs(codec); - /* sync the whole vmaster slaves to reflect the new auto-mute status */ + /* sync the whole vmaster followers to reflect the new auto-mute status */ if (spec->auto_mute_via_amp && !codec->bus->shutdown) snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); } @@ -5180,8 +5261,8 @@ * Build control elements */ -/* slave controls for virtual master */ -static const char * const slave_pfxs[] = { +/* follower controls for virtual master */ +static const char * const follower_pfxs[] = { "Front", "Surround", "Center", "LFE", "Side", "Headphone", "Speaker", "Mono", "Line Out", "CLFE", "Bass Speaker", "PCM", @@ -5233,7 +5314,7 @@ if (!spec->no_analog && !spec->suppress_vmaster && !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { err = snd_hda_add_vmaster(codec, "Master Playback Volume", - spec->vmaster_tlv, slave_pfxs, + spec->vmaster_tlv, follower_pfxs, "Playback Volume"); if (err < 0) return err; @@ -5241,7 +5322,7 @@ if (!spec->no_analog && !spec->suppress_vmaster && !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, + NULL, follower_pfxs, "Playback Switch", true, &spec->vmaster_mute.sw_kctl); if (err < 0) @@ -5756,7 +5837,7 @@ spec->stream_name_digital); if (!info) return -ENOMEM; - codec->slave_dig_outs = spec->multiout.slave_dig_outs; + codec->follower_dig_outs = spec->multiout.follower_dig_outs; spec->pcm_rec[1] = info; if (spec->dig_out_type) info->pcm_type = spec->dig_out_type; @@ -6023,7 +6104,7 @@ /* call init functions of standard auto-mute helpers */ update_automute_all(codec); - regcache_sync(codec->core.regmap); + snd_hda_regmap_sync(codec); if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) snd_hda_sync_vmaster_hook(&spec->vmaster_mute); -- Gitblit v1.6.2