diff options
Diffstat (limited to 'sound/pci/hda/hda_jack.c')
-rw-r--r-- | sound/pci/hda/hda_jack.c | 159 |
1 files changed, 60 insertions, 99 deletions
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 394901515d9e..d8a35da0803f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -90,15 +90,19 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_new); -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void snd_hda_input_jack_free(struct hda_codec *codec); -#else -#define snd_hda_input_jack_free(codec) -#endif - void snd_hda_jack_tbl_clear(struct hda_codec *codec) { - snd_hda_input_jack_free(codec); +#ifdef CONFIG_SND_HDA_INPUT_JACK + /* free jack instances manually when clearing/reconfiguring */ + if (!codec->bus->shutdown && codec->jacktbl.list) { + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + for (i = 0; i < codec->jacktbl.used; i++, jack++) { + if (jack->jack) + snd_device_free(codec->bus->card, jack->jack); + } + } +#endif snd_array_free(&codec->jacktbl); } @@ -199,10 +203,44 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) continue; state = get_jack_plug_state(jack->pin_sense); snd_kctl_jack_report(codec->bus->card, jack->kctl, state); +#ifdef CONFIG_SND_HDA_INPUT_JACK + if (jack->jack) + snd_jack_report(jack->jack, + state ? jack->type : 0); +#endif } } EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync); +#ifdef CONFIG_SND_HDA_INPUT_JACK +/* guess the jack type from the pin-config */ +static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + switch (get_defcfg_device(def_conf)) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + return SND_JACK_LINEOUT; + case AC_JACK_HP_OUT: + return SND_JACK_HEADPHONE; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + return SND_JACK_AVOUT; + case AC_JACK_MIC_IN: + return SND_JACK_MICROPHONE; + default: + return SND_JACK_LINEIN; + } +} + +static void hda_free_jack_priv(struct snd_jack *jack) +{ + struct hda_jack_tbl *jacks = jack->private_data; + jacks->nid = 0; + jacks->jack = NULL; +} +#endif + /** * snd_hda_jack_add_kctl - Add a kctl for the given pin * @@ -214,6 +252,7 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, { struct hda_jack_tbl *jack; struct snd_kcontrol *kctl; + int err, state; jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) @@ -223,11 +262,21 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, kctl = snd_kctl_jack_new(name, idx, codec); if (!kctl) return -ENOMEM; - if (snd_hda_ctl_add(codec, nid, kctl) < 0) - return -ENOMEM; + err = snd_hda_ctl_add(codec, nid, kctl); + if (err < 0) + return err; jack->kctl = kctl; - snd_kctl_jack_report(codec->bus->card, kctl, - snd_hda_jack_detect(codec, nid)); + state = snd_hda_jack_detect(codec, nid); + snd_kctl_jack_report(codec->bus->card, kctl, state); +#ifdef CONFIG_SND_HDA_INPUT_JACK + jack->type = get_input_jack_type(codec, nid); + err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack); + if (err < 0) + return err; + jack->jack->private_data = jack; + jack->jack->private_free = hda_free_jack_priv; + snd_jack_report(jack->jack, state ? jack->type : 0); +#endif return 0; } EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); @@ -302,91 +351,3 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, return 0; } EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls); - -#ifdef CONFIG_SND_HDA_INPUT_JACK -/* - * Input-jack notification support - */ -static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid, - int type) -{ - switch (type) { - case SND_JACK_HEADPHONE: - return "Headphone"; - case SND_JACK_MICROPHONE: - return "Mic"; - case SND_JACK_LINEOUT: - return "Line-out"; - case SND_JACK_LINEIN: - return "Line-in"; - case SND_JACK_HEADSET: - return "Headset"; - case SND_JACK_VIDEOOUT: - return "HDMI/DP"; - default: - return "Misc"; - } -} - -static void hda_free_jack_priv(struct snd_jack *jack) -{ - struct hda_jack_tbl *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} - -int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type, - const char *name) -{ - struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); - int err; - - if (!jack) - return -ENOMEM; - if (!name) - name = get_jack_default_name(codec, nid, type); - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) - return err; - jack->type = type; - jack->jack->private_data = jack; - jack->jack->private_free = hda_free_jack_priv; - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_input_jack_add); - -void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid) -{ - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); - unsigned int pin_ctl; - unsigned int present; - int type; - - if (!jack || !jack->jack) - return; - - present = snd_hda_jack_detect(codec, nid); - type = jack->type; - if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) { - pin_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - type = (pin_ctl & AC_PINCTL_HP_EN) ? - SND_JACK_HEADPHONE : SND_JACK_LINEOUT; - } - snd_jack_report(jack->jack, present ? type : 0); -} -EXPORT_SYMBOL_HDA(snd_hda_input_jack_report); - -/* free jack instances manually when clearing/reconfiguring */ -static void snd_hda_input_jack_free(struct hda_codec *codec) -{ - if (!codec->bus->shutdown && codec->jacktbl.list) { - struct hda_jack_tbl *jack = codec->jacktbl.list; - int i; - for (i = 0; i < codec->jacktbl.used; i++, jack++) { - if (jack->jack) - snd_device_free(codec->bus->card, jack->jack); - } - } -} -#endif /* CONFIG_SND_HDA_INPUT_JACK */ |