diff options
-rw-r--r-- | sound/pci/hda/hda_generic.c | 110 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 1 |
2 files changed, 111 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index fb4d84394b7b..55b7897444a0 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -1959,6 +1959,101 @@ static int create_shared_input(struct hda_codec *codec) | |||
1959 | return 0; | 1959 | return 0; |
1960 | } | 1960 | } |
1961 | 1961 | ||
1962 | /* | ||
1963 | * output jack mode | ||
1964 | */ | ||
1965 | static int out_jack_mode_info(struct snd_kcontrol *kcontrol, | ||
1966 | struct snd_ctl_elem_info *uinfo) | ||
1967 | { | ||
1968 | static const char * const texts[] = { | ||
1969 | "Line Out", "Headphone Out", | ||
1970 | }; | ||
1971 | return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); | ||
1972 | } | ||
1973 | |||
1974 | static int out_jack_mode_get(struct snd_kcontrol *kcontrol, | ||
1975 | struct snd_ctl_elem_value *ucontrol) | ||
1976 | { | ||
1977 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1978 | hda_nid_t nid = kcontrol->private_value; | ||
1979 | if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) | ||
1980 | ucontrol->value.enumerated.item[0] = 1; | ||
1981 | else | ||
1982 | ucontrol->value.enumerated.item[0] = 0; | ||
1983 | return 0; | ||
1984 | } | ||
1985 | |||
1986 | static int out_jack_mode_put(struct snd_kcontrol *kcontrol, | ||
1987 | struct snd_ctl_elem_value *ucontrol) | ||
1988 | { | ||
1989 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1990 | hda_nid_t nid = kcontrol->private_value; | ||
1991 | unsigned int val; | ||
1992 | |||
1993 | val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; | ||
1994 | if (snd_hda_codec_get_pin_target(codec, nid) == val) | ||
1995 | return 0; | ||
1996 | snd_hda_set_pin_ctl_cache(codec, nid, val); | ||
1997 | return 1; | ||
1998 | } | ||
1999 | |||
2000 | static const struct snd_kcontrol_new out_jack_mode_enum = { | ||
2001 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2002 | .info = out_jack_mode_info, | ||
2003 | .get = out_jack_mode_get, | ||
2004 | .put = out_jack_mode_put, | ||
2005 | }; | ||
2006 | |||
2007 | static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) | ||
2008 | { | ||
2009 | struct hda_gen_spec *spec = codec->spec; | ||
2010 | int i; | ||
2011 | |||
2012 | for (i = 0; i < spec->kctls.used; i++) { | ||
2013 | struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); | ||
2014 | if (!strcmp(kctl->name, name) && kctl->index == idx) | ||
2015 | return true; | ||
2016 | } | ||
2017 | return false; | ||
2018 | } | ||
2019 | |||
2020 | static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, | ||
2021 | char *name, size_t name_len) | ||
2022 | { | ||
2023 | struct hda_gen_spec *spec = codec->spec; | ||
2024 | int idx = 0; | ||
2025 | |||
2026 | snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); | ||
2027 | strlcat(name, " Jack Mode", name_len); | ||
2028 | |||
2029 | for (; find_kctl_name(codec, name, idx); idx++) | ||
2030 | ; | ||
2031 | } | ||
2032 | |||
2033 | static int create_out_jack_modes(struct hda_codec *codec, int num_pins, | ||
2034 | hda_nid_t *pins) | ||
2035 | { | ||
2036 | struct hda_gen_spec *spec = codec->spec; | ||
2037 | int i; | ||
2038 | |||
2039 | for (i = 0; i < num_pins; i++) { | ||
2040 | hda_nid_t pin = pins[i]; | ||
2041 | unsigned int pincap = snd_hda_query_pin_caps(codec, pin); | ||
2042 | if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { | ||
2043 | struct snd_kcontrol_new *knew; | ||
2044 | char name[44]; | ||
2045 | get_jack_mode_name(codec, pin, name, sizeof(name)); | ||
2046 | knew = snd_hda_gen_add_kctl(spec, name, | ||
2047 | &out_jack_mode_enum); | ||
2048 | if (!knew) | ||
2049 | return -ENOMEM; | ||
2050 | knew->private_value = pin; | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | return 0; | ||
2055 | } | ||
2056 | |||
1962 | 2057 | ||
1963 | /* | 2058 | /* |
1964 | * Parse input paths | 2059 | * Parse input paths |
@@ -3298,6 +3393,21 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
3298 | if (err < 0) | 3393 | if (err < 0) |
3299 | return err; | 3394 | return err; |
3300 | 3395 | ||
3396 | if (spec->add_out_jack_modes) { | ||
3397 | if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | ||
3398 | err = create_out_jack_modes(codec, cfg->line_outs, | ||
3399 | cfg->line_out_pins); | ||
3400 | if (err < 0) | ||
3401 | return err; | ||
3402 | } | ||
3403 | if (cfg->line_out_type != AUTO_PIN_HP_OUT) { | ||
3404 | err = create_out_jack_modes(codec, cfg->hp_outs, | ||
3405 | cfg->hp_pins); | ||
3406 | if (err < 0) | ||
3407 | return err; | ||
3408 | } | ||
3409 | } | ||
3410 | |||
3301 | dig_only: | 3411 | dig_only: |
3302 | parse_digital(codec); | 3412 | parse_digital(codec); |
3303 | 3413 | ||
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 89683c7fe263..bfa2d973268b 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -191,6 +191,7 @@ struct hda_gen_spec { | |||
191 | unsigned int indep_hp:1; /* independent HP supported */ | 191 | unsigned int indep_hp:1; /* independent HP supported */ |
192 | unsigned int indep_hp_enabled:1; /* independent HP enabled */ | 192 | unsigned int indep_hp_enabled:1; /* independent HP enabled */ |
193 | unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */ | 193 | unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */ |
194 | unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */ | ||
194 | 195 | ||
195 | /* loopback mixing mode */ | 196 | /* loopback mixing mode */ |
196 | bool aamix_mode; | 197 | bool aamix_mode; |