ALSA: hda - Make common input-jack helper functions
Takashi Iwai [Thu, 3 Mar 2011 13:40:14 +0000 (14:40 +0100)]
Since multiple codec drivers already use the input-jack stuff, let's
make common helper functions to reduce the duplicated codes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_local.h
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c

index ae5c5d5..2c79e96 100644 (file)
@@ -29,6 +29,7 @@
 #include <sound/asoundef.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
+#include <sound/jack.h>
 #include "hda_local.h"
 #include "hda_beep.h"
 #include <sound/hda_hwdep.h>
@@ -4959,5 +4960,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
 }
 EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
 
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+/*
+ * Input-jack notification support
+ */
+struct hda_jack_item {
+       hda_nid_t nid;
+       int type;
+       struct snd_jack *jack;
+};
+
+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_HEADSET:
+               return "Headset";
+       default:
+               return "Misc";
+       }
+}
+
+static void hda_free_jack_priv(struct snd_jack *jack)
+{
+       struct hda_jack_item *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_item *jack;
+       int err;
+
+       snd_array_init(&codec->jacks, sizeof(*jack), 32);
+       jack = snd_array_new(&codec->jacks);
+       if (!jack)
+               return -ENOMEM;
+
+       jack->nid = nid;
+       jack->type = type;
+       if (!name)
+               name = get_jack_default_name(codec, nid, type);
+       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+       if (err < 0) {
+               jack->nid = 0;
+               return err;
+       }
+       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_item *jacks = codec->jacks.list;
+       int i;
+
+       if (!jacks)
+               return;
+
+       for (i = 0; i < codec->jacks.used; i++, jacks++) {
+               unsigned int pin_ctl;
+               unsigned int present;
+               int type;
+
+               if (jacks->nid != nid)
+                       continue;
+               present = snd_hda_jack_detect(codec, nid);
+               type = jacks->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(jacks->jack, present ? type : 0);
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_jack_report);
+
+/* free jack instances manually when clearing/reconfiguring */
+void snd_hda_input_jack_free(struct hda_codec *codec)
+{
+       if (!codec->bus->shutdown && codec->jacks.list) {
+               struct hda_jack_item *jacks = codec->jacks.list;
+               int i;
+               for (i = 0; i < codec->jacks.used; i++, jacks++) {
+                       if (jacks->jack)
+                               snd_device_free(codec->bus->card, jacks->jack);
+               }
+       }
+       snd_array_free(&codec->jacks);
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_jack_free);
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
+
 MODULE_DESCRIPTION("HDA codec core");
 MODULE_LICENSE("GPL");
index fdf8d44..e46d542 100644 (file)
@@ -866,6 +866,11 @@ struct hda_codec {
        /* codec-specific additional proc output */
        void (*proc_widget_hook)(struct snd_info_buffer *buffer,
                                 struct hda_codec *codec, hda_nid_t nid);
+
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+       /* jack detection */
+       struct snd_array jacks;
+#endif
 };
 
 /* direction */
index 3ab5e7a..ff5e2ac 100644 (file)
@@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
 #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
 
+/*
+ * Input-jack notification support
+ */
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
+                          const char *name);
+void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
+void snd_hda_input_jack_free(struct hda_codec *codec);
+#else /* CONFIG_SND_HDA_INPUT_JACK */
+static inline int snd_hda_input_jack_add(struct hda_codec *codec,
+                                        hda_nid_t nid, int type,
+                                        const char *name)
+{
+       return 0;
+}
+static inline void snd_hda_input_jack_report(struct hda_codec *codec,
+                                            hda_nid_t nid)
+{
+}
+static inline void snd_hda_input_jack_free(struct hda_codec *codec)
+{
+}
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
+
 #endif /* __SOUND_HDA_LOCAL_H */
index 4d5004e..d08cf31 100644 (file)
 #define AUTO_MIC_PORTB         (1 << 1)
 #define AUTO_MIC_PORTC         (1 << 2)
 
-struct conexant_jack {
-
-       hda_nid_t nid;
-       int type;
-       struct snd_jack *jack;
-
-};
-
 struct pin_dac_pair {
        hda_nid_t pin;
        hda_nid_t dac;
@@ -111,9 +103,6 @@ struct conexant_spec {
 
        unsigned int spdif_route;
 
-       /* jack detection */
-       struct snd_array jacks;
-
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct hda_input_mux private_imux;
@@ -393,71 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
                                     &spec->cur_mux[adc_idx]);
 }
 
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void conexant_free_jack_priv(struct snd_jack *jack)
-{
-       struct conexant_jack *jacks = jack->private_data;
-       jacks->nid = 0;
-       jacks->jack = NULL;
-}
-
-static int conexant_add_jack(struct hda_codec *codec,
-               hda_nid_t nid, int type)
-{
-       struct conexant_spec *spec;
-       struct conexant_jack *jack;
-       const char *name;
-       int i, err;
-
-       spec = codec->spec;
-       snd_array_init(&spec->jacks, sizeof(*jack), 32);
-
-       jack = spec->jacks.list;
-       for (i = 0; i < spec->jacks.used; i++, jack++)
-               if (jack->nid == nid)
-                       return 0 ; /* already present */
-
-       jack = snd_array_new(&spec->jacks);
-       name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
-
-       if (!jack)
-               return -ENOMEM;
-
-       jack->nid = nid;
-       jack->type = type;
-
-       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
-       if (err < 0)
-               return err;
-       jack->jack->private_data = jack;
-       jack->jack->private_free = conexant_free_jack_priv;
-       return 0;
-}
-
-static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct conexant_spec *spec = codec->spec;
-       struct conexant_jack *jacks = spec->jacks.list;
-
-       if (jacks) {
-               int i;
-               for (i = 0; i < spec->jacks.used; i++) {
-                       if (jacks->nid == nid) {
-                               unsigned int present;
-                               present = snd_hda_jack_detect(codec, nid);
-
-                               present = (present) ? jacks->type : 0 ;
-
-                               snd_jack_report(jacks->jack,
-                                               present);
-                       }
-                       jacks++;
-               }
-       }
-}
-
 static int conexant_init_jacks(struct hda_codec *codec)
 {
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        struct conexant_spec *spec = codec->spec;
        int i;
 
@@ -469,15 +396,15 @@ static int conexant_init_jacks(struct hda_codec *codec)
                        int err = 0;
                        switch (hv->param ^ AC_USRSP_EN) {
                        case CONEXANT_HP_EVENT:
-                               err = conexant_add_jack(codec, hv->nid,
-                                               SND_JACK_HEADPHONE);
-                               conexant_report_jack(codec, hv->nid);
+                               err = snd_hda_input_jack_add(codec, hv->nid,
+                                               SND_JACK_HEADPHONE, NULL);
+                               snd_hda_input_jack_report(codec, hv->nid);
                                break;
                        case CXT5051_PORTC_EVENT:
                        case CONEXANT_MIC_EVENT:
-                               err = conexant_add_jack(codec, hv->nid,
-                                               SND_JACK_MICROPHONE);
-                               conexant_report_jack(codec, hv->nid);
+                               err = snd_hda_input_jack_add(codec, hv->nid,
+                                               SND_JACK_MICROPHONE, NULL);
+                               snd_hda_input_jack_report(codec, hv->nid);
                                break;
                        }
                        if (err < 0)
@@ -485,19 +412,9 @@ static int conexant_init_jacks(struct hda_codec *codec)
                        ++hv;
                }
        }
-       return 0;
-
-}
-#else
-static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-}
-
-static inline int conexant_init_jacks(struct hda_codec *codec)
-{
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
        return 0;
 }
-#endif
 
 static int conexant_init(struct hda_codec *codec)
 {
@@ -511,18 +428,7 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       struct conexant_spec *spec = codec->spec;
-       if (spec->jacks.list) {
-               struct conexant_jack *jacks = spec->jacks.list;
-               int i;
-               for (i = 0; i < spec->jacks.used; i++, jacks++) {
-                       if (jacks->jack)
-                               snd_device_free(codec->bus->card, jacks->jack);
-               }
-               snd_array_free(&spec->jacks);
-       }
-#endif
+       snd_hda_input_jack_free(codec);
        snd_hda_detach_beep_device(codec);
        kfree(codec->spec);
 }
@@ -1787,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
                cxt5051_portc_automic(codec);
                break;
        }
-       conexant_report_jack(codec, nid);
+       snd_hda_input_jack_report(codec, nid);
 }
 
 static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
@@ -1959,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0,
                            AC_VERB_SET_UNSOLICITED_ENABLE,
                            AC_USRSP_EN | event);
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
-       conexant_report_jack(codec, nid);
-#endif
+       snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
+       snd_hda_input_jack_report(codec, nid);
 }
 
 static struct hda_verb cxt5051_ideapad_init_verbs[] = {
@@ -3477,11 +3381,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cx_auto_hp_automute(codec);
-               conexant_report_jack(codec, nid);
+               snd_hda_input_jack_report(codec, nid);
                break;
        case CONEXANT_MIC_EVENT:
                cx_auto_automic(codec);
-               conexant_report_jack(codec, nid);
+               snd_hda_input_jack_report(codec, nid);
                break;
        }
 }
index 96cb442..f6c3441 100644 (file)
@@ -282,12 +282,6 @@ struct alc_mic_route {
        unsigned char amix_idx;
 };
 
-struct alc_jack {
-       hda_nid_t nid;
-       int type;
-       struct snd_jack *jack;
-};
-
 #define MUX_IDX_UNDEF  ((unsigned char)-1)
 
 struct alc_customize_define {
@@ -366,9 +360,6 @@ struct alc_spec {
        /* PCM information */
        struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
-       /* jack detection */
-       struct snd_array jacks;
-
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct alc_customize_define cdefine;
@@ -1032,94 +1023,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void alc_free_jack_priv(struct snd_jack *jack)
-{
-       struct alc_jack *jacks = jack->private_data;
-       jacks->nid = 0;
-       jacks->jack = NULL;
-}
-
-static int alc_add_jack(struct hda_codec *codec,
-               hda_nid_t nid, int type)
-{
-       struct alc_spec *spec;
-       struct alc_jack *jack;
-       const char *name;
-       int err;
-
-       spec = codec->spec;
-       snd_array_init(&spec->jacks, sizeof(*jack), 32);
-       jack = snd_array_new(&spec->jacks);
-       if (!jack)
-               return -ENOMEM;
-
-       jack->nid = nid;
-       jack->type = type;
-       name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
-
-       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
-       if (err < 0)
-               return err;
-       jack->jack->private_data = jack;
-       jack->jack->private_free = alc_free_jack_priv;
-       return 0;
-}
-
-static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct alc_spec *spec = codec->spec;
-       struct alc_jack *jacks = spec->jacks.list;
-
-       if (jacks) {
-               int i;
-               for (i = 0; i < spec->jacks.used; i++) {
-                       if (jacks->nid == nid) {
-                               unsigned int present;
-                               present = snd_hda_jack_detect(codec, nid);
-
-                               present = (present) ? jacks->type : 0;
-
-                               snd_jack_report(jacks->jack, present);
-                       }
-                       jacks++;
-               }
-       }
-}
-
 static int alc_init_jacks(struct hda_codec *codec)
 {
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        struct alc_spec *spec = codec->spec;
        int err;
        unsigned int hp_nid = spec->autocfg.hp_pins[0];
        unsigned int mic_nid = spec->ext_mic.pin;
 
        if (hp_nid) {
-               err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+               err = snd_hda_input_jack_add(codec, hp_nid,
+                                            SND_JACK_HEADPHONE, NULL);
                if (err < 0)
                        return err;
-               alc_report_jack(codec, hp_nid);
+               snd_hda_input_jack_report(codec, hp_nid);
        }
 
        if (mic_nid) {
-               err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+               err = snd_hda_input_jack_add(codec, mic_nid,
+                                            SND_JACK_MICROPHONE, NULL);
                if (err < 0)
                        return err;
-               alc_report_jack(codec, mic_nid);
+               snd_hda_input_jack_report(codec, mic_nid);
        }
-
-       return 0;
-}
-#else
-static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-}
-
-static inline int alc_init_jacks(struct hda_codec *codec)
-{
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
        return 0;
 }
-#endif
 
 static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
 {
@@ -1133,7 +1062,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
-               alc_report_jack(codec, nid);
+               snd_hda_input_jack_report(codec, nid);
                spec->jack_present |= snd_hda_jack_detect(codec, nid);
        }
 
@@ -1240,7 +1169,7 @@ static void alc_mic_automute(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL,
                                          alive->mux_idx);
        }
-       alc_report_jack(codec, spec->ext_mic.pin);
+       snd_hda_input_jack_report(codec, spec->ext_mic.pin);
 
        /* FIXME: analog mixer */
 }
@@ -4283,6 +4212,7 @@ static void alc_free(struct hda_codec *codec)
                return;
 
        alc_shutup(codec);
+       snd_hda_input_jack_free(codec);
        alc_free_kctls(codec);
        kfree(spec);
        snd_hda_detach_beep_device(codec);
@@ -14494,7 +14424,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, bits);
-       alc_report_jack(codec, nid);
+       snd_hda_input_jack_report(codec, nid);
 }
 
 /* unsolicited event for HP jack sensing */
index bd7b123..8fe5608 100644 (file)
@@ -180,12 +180,6 @@ struct sigmatel_event {
        int data;
 };
 
-struct sigmatel_jack {
-       hda_nid_t nid;
-       int type;
-       struct snd_jack *jack;
-};
-
 struct sigmatel_mic_route {
        hda_nid_t pin;
        signed char mux_idx;
@@ -229,9 +223,6 @@ struct sigmatel_spec {
        hda_nid_t *pwr_nids;
        hda_nid_t *dac_list;
 
-       /* jack detection */
-       struct snd_array jacks;
-
        /* events */
        struct snd_array events;
 
@@ -4054,21 +4045,10 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
                           AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void stac92xx_free_jack_priv(struct snd_jack *jack)
-{
-       struct sigmatel_jack *jacks = jack->private_data;
-       jacks->nid = 0;
-       jacks->jack = NULL;
-}
-#endif
-
 static int stac92xx_add_jack(struct hda_codec *codec,
                hda_nid_t nid, int type)
 {
 #ifdef CONFIG_SND_HDA_INPUT_JACK
-       struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_jack *jack;
        int def_conf = snd_hda_codec_get_pincfg(codec, nid);
        int connectivity = get_defcfg_connect(def_conf);
        char name[32];
@@ -4077,26 +4057,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
        if (connectivity && connectivity != AC_JACK_PORT_FIXED)
                return 0;
 
-       snd_array_init(&spec->jacks, sizeof(*jack), 32);
-       jack = snd_array_new(&spec->jacks);
-       if (!jack)
-               return -ENOMEM;
-       jack->nid = nid;
-       jack->type = type;
-
        snprintf(name, sizeof(name), "%s at %s %s Jack",
                snd_hda_get_jack_type(def_conf),
                snd_hda_get_jack_connectivity(def_conf),
                snd_hda_get_jack_location(def_conf));
 
-       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
-       if (err < 0) {
-               jack->nid = 0;
+       err = snd_hda_input_jack_add(codec, nid, type, name);
+       if (err < 0)
                return err;
-       }
-       jack->jack->private_data = jack;
-       jack->jack->private_free = stac92xx_free_jack_priv;
-#endif
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
        return 0;
 }
 
@@ -4399,23 +4368,6 @@ static int stac92xx_init(struct hda_codec *codec)
        return 0;
 }
 
-static void stac92xx_free_jacks(struct hda_codec *codec)
-{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       /* free jack instances manually when clearing/reconfiguring */
-       struct sigmatel_spec *spec = codec->spec;
-       if (!codec->bus->shutdown && spec->jacks.list) {
-               struct sigmatel_jack *jacks = spec->jacks.list;
-               int i;
-               for (i = 0; i < spec->jacks.used; i++, jacks++) {
-                       if (jacks->jack)
-                               snd_device_free(codec->bus->card, jacks->jack);
-               }
-       }
-       snd_array_free(&spec->jacks);
-#endif
-}
-
 static void stac92xx_free_kctls(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4449,7 +4401,7 @@ static void stac92xx_free(struct hda_codec *codec)
                return;
 
        stac92xx_shutup(codec);
-       stac92xx_free_jacks(codec);
+       snd_hda_input_jack_free(codec);
        snd_array_free(&spec->events);
 
        kfree(spec);
@@ -4667,33 +4619,6 @@ static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
        stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
 }
 
-static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_jack *jacks = spec->jacks.list;
-
-       if (jacks) {
-               int i;
-               for (i = 0; i < spec->jacks.used; i++) {
-                       if (jacks->nid == nid) {
-                               unsigned int pin_ctl =
-                                       snd_hda_codec_read(codec, nid,
-                                       0, AC_VERB_GET_PIN_WIDGET_CONTROL,
-                                        0x00);
-                               int type = jacks->type;
-                               if (type == (SND_JACK_LINEOUT
-                                               | SND_JACK_HEADPHONE))
-                                       type = (pin_ctl & AC_PINCTL_HP_EN)
-                                       ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
-                               snd_jack_report(jacks->jack,
-                                       get_pin_presence(codec, nid)
-                                       ? type : 0);
-                       }
-                       jacks++;
-               }
-       }
-}
-
 /* get the pin connection (fixed, none, etc) */
 static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
 {
@@ -4782,7 +4707,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
        case STAC_PWR_EVENT:
                if (spec->num_pwrs > 0)
                        stac92xx_pin_sense(codec, event->nid);
-               stac92xx_report_jack(codec, event->nid);
+               snd_hda_input_jack_report(codec, event->nid);
 
                switch (codec->subsystem_id) {
                case 0x103c308f: