summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_jack.c')
-rw-r--r--sound/pci/hda/hda_jack.c159
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 */