#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>
}
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");
/* 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 */
#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 */
#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;
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;
&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;
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)
++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)
{
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);
}
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[] = {
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[] = {
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;
}
}
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 {
/* 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;
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)
{
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);
}
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 */
}
return;
alc_shutup(codec);
+ snd_hda_input_jack_free(codec);
alc_free_kctls(codec);
kfree(spec);
snd_hda_detach_beep_device(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 */
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;
hda_nid_t *pwr_nids;
hda_nid_t *dac_list;
- /* jack detection */
- struct snd_array jacks;
-
/* events */
struct snd_array events;
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];
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;
}
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;
return;
stac92xx_shutup(codec);
- stac92xx_free_jacks(codec);
+ snd_hda_input_jack_free(codec);
snd_array_free(&spec->events);
kfree(spec);
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)
{
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: