diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-01-10 10:57:58 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-12 02:44:38 -0500 |
commit | 978e77e78cff7a85a31ad552ffd8afee319e8721 (patch) | |
tree | c95b0e607f72f3549817fd992999e8251adfe96a | |
parent | a365fed9806e182cb4e1b7bb1855759489d95858 (diff) |
ALSA: hda - Add output jack mode enum controls
Add the enum controls for changing the headphone amp bits of output
jacks, such as "Headphone Jack Mode". This feature isn't enabled as
default, so far, unless spec->add_out_jack_modes flag is set.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-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; |