aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_generic.c')
-rw-r--r--sound/pci/hda/hda_generic.c99
1 files changed, 71 insertions, 28 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index c7f6d1cab606..8321a97d5c05 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/bitops.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
@@ -47,7 +48,7 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
mutex_init(&spec->pcm_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init);
+EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
@@ -65,7 +66,7 @@ snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
return NULL;
return knew;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl);
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl);
static void free_kctls(struct hda_gen_spec *spec)
{
@@ -86,7 +87,7 @@ void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
snd_array_free(&spec->paths);
snd_array_free(&spec->loopback_list);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free);
+EXPORT_SYMBOL_GPL(snd_hda_gen_spec_free);
/*
* store user hints
@@ -266,7 +267,7 @@ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
{
return get_nid_path(codec, from_nid, to_nid, 0);
}
-EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
+EXPORT_SYMBOL_GPL(snd_hda_get_nid_path);
/* get the index number corresponding to the path instance;
* the index starts from 1, for easier checking the invalid value
@@ -284,7 +285,7 @@ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
return 0;
return idx + 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_path_idx);
+EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
/* get the path instance corresponding to the given index number */
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
@@ -295,7 +296,7 @@ struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
return NULL;
return snd_array_elem(&spec->paths, idx - 1);
}
-EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx);
+EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx);
/* check whether the given DAC is already found in any existing paths */
static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
@@ -432,7 +433,7 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
}
return false;
}
-EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path);
+EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path);
/*
* parse the path between the given NIDs and add to the path list.
@@ -463,7 +464,7 @@ snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
spec->paths.used--;
return NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_new_path);
+EXPORT_SYMBOL_GPL(snd_hda_add_new_path);
/* clear the given path as invalid so that it won't be picked up later */
static void invalidate_nid_path(struct hda_codec *codec, int idx)
@@ -773,7 +774,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
if (enable)
path->active = true;
}
-EXPORT_SYMBOL_HDA(snd_hda_activate_path);
+EXPORT_SYMBOL_GPL(snd_hda_activate_path);
/* if the given path is inactive, put widgets into D3 (only if suitable) */
static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
@@ -1149,7 +1150,7 @@ const struct badness_table hda_main_out_badness = {
.shared_clfe = BAD_SHARED_CLFE,
.shared_surr_main = BAD_SHARED_SURROUND,
};
-EXPORT_SYMBOL_HDA(hda_main_out_badness);
+EXPORT_SYMBOL_GPL(hda_main_out_badness);
const struct badness_table hda_extra_out_badness = {
.no_primary_dac = BAD_NO_DAC,
@@ -1159,7 +1160,7 @@ const struct badness_table hda_extra_out_badness = {
.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
};
-EXPORT_SYMBOL_HDA(hda_extra_out_badness);
+EXPORT_SYMBOL_GPL(hda_extra_out_badness);
/* get the DAC of the primary output corresponding to the given array index */
static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
@@ -2857,9 +2858,11 @@ static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
if (num_conns < idx)
return false;
nid = list[idx];
- if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT))
+ if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) &&
+ !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL))
*mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT))
+ if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) &&
+ !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL))
*mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
return *mix_val || *mute_val;
@@ -3053,6 +3056,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
spec->imux_pins[imux->num_items] = pin;
snd_hda_add_imux_item(imux, label, cfg_idx, NULL);
imux_added = true;
+ if (spec->dyn_adc_switch)
+ spec->dyn_adc_idx[imux_idx] = c;
}
}
@@ -3150,7 +3155,9 @@ static int create_input_ctls(struct hda_codec *codec)
}
}
- if (mixer && spec->add_stereo_mix_input) {
+ /* add stereo mix when explicitly enabled via hint */
+ if (mixer && spec->add_stereo_mix_input &&
+ snd_hda_get_bool_hint(codec, "add_stereo_mix_input") > 0) {
err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
"Stereo Mix", 0);
if (err < 0)
@@ -3916,7 +3923,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins, paths, on);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
+EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs);
static void call_update_outputs(struct hda_codec *codec)
{
@@ -3949,7 +3956,7 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
return;
call_update_outputs(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute);
+EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
/* standard line-out-automute helper */
void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
@@ -3969,7 +3976,7 @@ void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jac
return;
call_update_outputs(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute);
+EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
/* standard mic auto-switch helper */
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
@@ -3992,7 +3999,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
}
mux_select(codec, 0, spec->am_entry[0].idx);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch);
+EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
/* call appropriate hooks */
static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
@@ -4305,11 +4312,11 @@ static int check_auto_mic_availability(struct hda_codec *codec)
}
/* power_filter hook; make inactive widgets into power down */
-static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
+unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
{
- if (power_state != AC_PWRST_D0)
+ if (power_state != AC_PWRST_D0 || nid == codec->afg)
return power_state;
if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
return power_state;
@@ -4317,6 +4324,7 @@ static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
return power_state;
return AC_PWRST_D3;
}
+EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter);
/* mute all aamix inputs initially; parse up to the first leaves */
static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
@@ -4374,7 +4382,8 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
spec->no_analog = 1;
goto dig_only;
}
- return 0; /* can't find valid BIOS pin config */
+ if (!cfg->num_inputs && !cfg->dig_in_pin)
+ return 0; /* can't find valid BIOS pin config */
}
if (!spec->no_primary_hp &&
@@ -4442,6 +4451,19 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
if (err < 0)
return err;
+ /* add stereo mix if available and not enabled yet */
+ if (!spec->auto_mic && spec->mixer_nid &&
+ spec->add_stereo_mix_input &&
+ spec->input_mux.num_items > 1 &&
+ snd_hda_get_bool_hint(codec, "add_stereo_mix_input") < 0) {
+ err = parse_capture_source(codec, spec->mixer_nid,
+ CFG_IDX_MIX, spec->num_all_adcs,
+ "Stereo Mix", 0);
+ if (err < 0)
+ return err;
+ }
+
+
err = create_capture_mixers(codec);
if (err < 0)
return err;
@@ -4494,7 +4516,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
return 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
+EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config);
/*
@@ -4576,7 +4598,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
+EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls);
/*
@@ -5109,7 +5131,7 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms);
+EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms);
/*
@@ -5183,6 +5205,23 @@ static void init_multi_io(struct hda_codec *codec)
}
}
+static void init_aamix_paths(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ if (!spec->have_aamix_ctl)
+ return;
+ update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
+ spec->aamix_out_paths[0],
+ spec->autocfg.line_out_type);
+ update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0],
+ spec->aamix_out_paths[1],
+ AUTO_PIN_HP_OUT);
+ update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0],
+ spec->aamix_out_paths[2],
+ AUTO_PIN_SPEAKER_OUT);
+}
+
/* set up input pins and loopback paths */
static void init_analog_input(struct hda_codec *codec)
{
@@ -5285,6 +5324,7 @@ int snd_hda_gen_init(struct hda_codec *codec)
init_multi_out(codec);
init_extra_out(codec);
init_multi_io(codec);
+ init_aamix_paths(codec);
init_analog_input(codec);
init_input_src(codec);
init_digital(codec);
@@ -5302,7 +5342,7 @@ int snd_hda_gen_init(struct hda_codec *codec)
hda_call_check_power_status(codec, 0x01);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_init);
+EXPORT_SYMBOL_GPL(snd_hda_gen_init);
/*
* free the generic spec;
@@ -5315,7 +5355,7 @@ void snd_hda_gen_free(struct hda_codec *codec)
kfree(codec->spec);
codec->spec = NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_free);
+EXPORT_SYMBOL_GPL(snd_hda_gen_free);
#ifdef CONFIG_PM
/*
@@ -5327,7 +5367,7 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
struct hda_gen_spec *spec = codec->spec;
return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status);
+EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
#endif
@@ -5372,4 +5412,7 @@ error:
snd_hda_gen_free(codec);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec);
+EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic HD-audio codec parser");