From 04f5ade6afc4326dc6cd10d235500972fba548eb Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Thu, 27 Oct 2011 20:47:07 +0200 Subject: ALSA: hda - Introduce snd_hda_get_pin_label() Create a new helper function snd_hda_get_pin_label() for getting a label string for both input and output pins. hda_get_input_pin_label() is obsoleted by this function, and the callers are replaced appropriately now by this patch. Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_codec.c | 63 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) (limited to 'sound/pci/hda/hda_codec.c') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e44b107fdc75..c6ff9b9de553 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5004,8 +5004,8 @@ EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); * "Rear", "Internal". */ -const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, - int check_location) +static const char *hda_get_input_pin_label(struct hda_codec *codec, + hda_nid_t pin, bool check_location) { unsigned int def_conf; static const char * const mic_names[] = { @@ -5044,7 +5044,6 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, return "Misc"; } } -EXPORT_SYMBOL_HDA(hda_get_input_pin_label); /* Check whether the location prefix needs to be added to the label. * If all mic-jacks are in the same location (e.g. rear panel), we don't @@ -5101,6 +5100,64 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); +/** + * snd_hda_get_pin_label - Get a label for the given I/O pin + * + * Get a label for the given pin. This function works for both input and + * output pins. When @cfg is given as non-NULL, the function tries to get + * an optimized label using hda_get_autocfg_input_label(). + */ +const char *snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int attr; + int i; + + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + return NULL; + + attr = snd_hda_get_input_pin_attr(def_conf); + switch (get_defcfg_device(def_conf)) { + case AC_JACK_LINE_OUT: + switch (attr) { + case INPUT_PIN_ATTR_INT: + return "Speaker"; + case INPUT_PIN_ATTR_DOCK: + return "Dock Line-Out"; + case INPUT_PIN_ATTR_FRONT: + return "Front Line-Out"; + default: + return "Line-Out"; + } + case AC_JACK_SPEAKER: + return "Speaker"; + case AC_JACK_HP_OUT: + switch (attr) { + case INPUT_PIN_ATTR_DOCK: + return "Dock Headphone"; + case INPUT_PIN_ATTR_FRONT: + return "Front Headphone"; + default: + return "Headphone"; + } + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI) + return "HDMI"; + else + return "SPDIF"; + } + + if (cfg) { + for (i = 0; i < cfg->num_inputs; i++) + if (cfg->inputs[i].pin == nid) + return hda_get_autocfg_input_label(codec, cfg, i); + } + return hda_get_input_pin_label(codec, nid, true); +} +EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); + /** * snd_hda_add_imux_item - Add an item to input_mux * -- cgit v1.2.3 From 1835a0f9a2121ce3198dab67507d4d3e960cc09e Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Thu, 27 Oct 2011 22:12:46 +0200 Subject: ALSA: hda - Cache the jack-detection value Introduce a table containing the pins and their jack-detection states for avoiding the unnecessary verbs to check the pin status at each time. When the unsol event is enabled via snd_hda_jack_detect_enable(), it automatically adds the given NID to the table. Then the driver supposes that the codec driver will set the dirty flag appropariately when an unsolicited event is invoked for that pin. The behavior for reading other pins that aren't registered in the table doesn't change. Only the pins assigned to the table are cached, so far. In near futre, this table can be extended to use the central place for the unsolicited events of all pins, etc, and eventually include the jack-detect kcontrols that replace the current input-jack stuff. Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/Makefile | 2 +- sound/pci/hda/hda_codec.c | 40 +---------- sound/pci/hda/hda_codec.h | 3 + sound/pci/hda/hda_jack.c | 148 +++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_jack.h | 63 ++++++++++++++++++ sound/pci/hda/hda_local.h | 15 ----- sound/pci/hda/patch_analog.c | 1 + sound/pci/hda/patch_cirrus.c | 18 +++-- sound/pci/hda/patch_conexant.c | 20 +++--- sound/pci/hda/patch_hdmi.c | 6 +- sound/pci/hda/patch_realtek.c | 20 +++--- sound/pci/hda/patch_sigmatel.c | 46 +++++++------ sound/pci/hda/patch_via.c | 19 +++--- 13 files changed, 284 insertions(+), 117 deletions(-) create mode 100644 sound/pci/hda/hda_jack.c create mode 100644 sound/pci/hda/hda_jack.h (limited to 'sound/pci/hda/hda_codec.c') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index f928d6634723..ace157cc3d15 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,6 @@ snd-hda-intel-objs := hda_intel.o -snd-hda-codec-y := hda_codec.o +snd-hda-codec-y := hda_codec.o hda_jack.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c6ff9b9de553..8217ff7ff7b5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -33,6 +33,7 @@ #include <sound/jack.h> #include "hda_local.h" #include "hda_beep.h" +#include "hda_jack.h" #include <sound/hda_hwdep.h> #define CREATE_TRACE_POINTS @@ -1723,43 +1724,6 @@ int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps); -/** - * snd_hda_pin_sense - execute pin sense measurement - * @codec: the CODEC to sense - * @nid: the pin NID to sense - * - * Execute necessary pin sense measurement and return its Presence Detect, - * Impedance, ELD Valid etc. status bits. - */ -u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) -{ - u32 pincap; - - if (!codec->no_trigger_sense) { - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ - snd_hda_codec_read(codec, nid, 0, - AC_VERB_SET_PIN_SENSE, 0); - } - return snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); -} -EXPORT_SYMBOL_HDA(snd_hda_pin_sense); - -/** - * snd_hda_jack_detect - query pin Presence Detect status - * @codec: the CODEC to sense - * @nid: the pin NID to sense - * - * Query and return the pin's Presence Detect status. - */ -int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) -{ - u32 sense = snd_hda_pin_sense(codec, nid); - return !!(sense & AC_PINSENSE_PRESENCE); -} -EXPORT_SYMBOL_HDA(snd_hda_jack_detect); - /* * read the current volume to info * if the cache exists, read the cache value. @@ -2308,6 +2272,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) } if (codec->patch_ops.free) codec->patch_ops.free(codec); + snd_hda_jack_tbl_clear(codec); codec->proc_widget_hook = NULL; codec->spec = NULL; free_hda_cache(&codec->amp_cache); @@ -3364,6 +3329,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) restore_pincfgs(codec); /* restore all current pin configs */ restore_shutup_pins(codec); hda_exec_init_verbs(codec); + snd_hda_jack_set_dirty_all(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 564471169cae..97aa65d1f1d1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -869,6 +869,9 @@ struct hda_codec { void (*proc_widget_hook)(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid); + /* jack detection */ + struct snd_array jacktbl; + #ifdef CONFIG_SND_HDA_INPUT_JACK /* jack detection */ struct snd_array jacks; diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c new file mode 100644 index 000000000000..64b78a2e20e0 --- /dev/null +++ b/sound/pci/hda/hda_jack.c @@ -0,0 +1,148 @@ +/* + * Jack-detection handling for HD-audio + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <sound/core.h> +#include "hda_codec.h" +#include "hda_local.h" +#include "hda_jack.h" + +/* execute pin sense measurement */ +static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) +{ + u32 pincap; + + if (!codec->no_trigger_sense) { + pincap = snd_hda_query_pin_caps(codec, nid); + if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ + snd_hda_codec_read(codec, nid, 0, + AC_VERB_SET_PIN_SENSE, 0); + } + return snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); +} + +/** + * snd_hda_jack_tbl_get - query the jack-table entry for the given NID + */ +struct hda_jack_tbl * +snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + + if (!nid || !jack) + return NULL; + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid == nid) + return jack; + return NULL; +} +EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get); + +/** + * snd_hda_jack_tbl_new - create a jack-table entry for the given NID + */ +struct hda_jack_tbl * +snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + if (jack) + return jack; + snd_array_init(&codec->jacktbl, sizeof(*jack), 16); + jack = snd_array_new(&codec->jacktbl); + if (!jack) + return NULL; + jack->nid = nid; + jack->jack_dirty = 1; + return jack; +} + +void snd_hda_jack_tbl_clear(struct hda_codec *codec) +{ + snd_array_free(&codec->jacktbl); +} + +/* update the cached value and notification flag if needed */ +static void jack_detect_update(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + if (jack->jack_dirty) { + jack->pin_sense = read_pin_sense(codec, jack->nid); + jack->jack_dirty = 0; + } +} + +/** + * snd_hda_set_dirty_all - Mark all the cached as dirty + * + * This function sets the dirty flag to all entries of jack table. + * It's called from the resume path in hda_codec.c. + */ +void snd_hda_jack_set_dirty_all(struct hda_codec *codec) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid) + jack->jack_dirty = 1; +} +EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all); + +/** + * snd_hda_pin_sense - execute pin sense measurement + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Execute necessary pin sense measurement and return its Presence Detect, + * Impedance, ELD Valid etc. status bits. + */ +u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + if (jack) { + jack_detect_update(codec, jack); + return jack->pin_sense; + } + return read_pin_sense(codec, nid); +} +EXPORT_SYMBOL_HDA(snd_hda_pin_sense); + +/** + * snd_hda_jack_detect - query pin Presence Detect status + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Query and return the pin's Presence Detect status. + */ +int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +{ + u32 sense = snd_hda_pin_sense(codec, nid); + return !!(sense & AC_PINSENSE_PRESENCE); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_detect); + +/** + * snd_hda_jack_detect_enable - enable the jack-detection + */ +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, + unsigned int tag) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); + if (!jack) + return -ENOMEM; + return snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h new file mode 100644 index 000000000000..5c1bcb8cf565 --- /dev/null +++ b/sound/pci/hda/hda_jack.h @@ -0,0 +1,63 @@ +/* + * Jack-detection handling for HD-audio + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __SOUND_HDA_JACK_H +#define __SOUND_HDA_JACK_H + +struct hda_jack_tbl { + hda_nid_t nid; + unsigned int pin_sense; /* cached pin-sense value */ + unsigned int jack_dirty:1; /* needs to update? */ +}; + +struct hda_jack_tbl * +snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid); + +struct hda_jack_tbl * +snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid); +void snd_hda_jack_tbl_clear(struct hda_codec *codec); + +/** + * snd_hda_jack_set_dirty - set the dirty flag for the given jack-entry + * + * Call this function when a pin-state may change, e.g. when the hardware + * notifies via an unsolicited event. + */ +static inline void snd_hda_jack_set_dirty(struct hda_codec *codec, + hda_nid_t nid) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + if (jack) + jack->jack_dirty = 1; +} + +void snd_hda_jack_set_dirty_all(struct hda_codec *codec); + +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, + unsigned int tag); + +u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); + +static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) +{ + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) + return false; + if (!codec->ignore_misc_bit && + (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE)) + return false; + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + return false; + return true; +} + +#endif /* __SOUND_HDA_JACK_H */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7a10fe95211e..08e88b826d27 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -505,21 +505,6 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, unsigned int caps); -u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); - -static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) -{ - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) - return false; - if (!codec->ignore_misc_bit && - (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) - return false; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) - return false; - return true; -} /* flags for hda_nid_item */ #define HDA_NID_ITEM_AMP (1<<0) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index bcb3310c394f..9cb14b42dfff 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -29,6 +29,7 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_beep.h" +#include "hda_jack.h" struct ad198x_spec { const struct snd_kcontrol_new *mixers[6]; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 34a460bd27bb..6f158777f71a 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -26,6 +26,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_jack.h" #include <sound/tlv.h> /* @@ -1020,9 +1021,7 @@ static void init_output(struct hda_codec *codec) if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | HP_EVENT); + snd_hda_jack_detect_enable(codec, nid, HP_EVENT); spec->hp_detect = 1; } } @@ -1063,9 +1062,7 @@ static void init_input(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(spec->adc_idx[i])); if (spec->mic_detect && spec->automic_idx == i) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | MIC_EVENT); + snd_hda_jack_detect_enable(codec, pin, MIC_EVENT); } /* specific to CS421x */ if (spec->vendor_nid == CS421X_VENDOR_NID) { @@ -1227,6 +1224,8 @@ static void cs_free(struct hda_codec *codec) static void cs_unsol_event(struct hda_codec *codec, unsigned int res) { + snd_hda_jack_set_dirty_all(codec); /* FIXME: to be more fine-grained */ + switch ((res >> 26) & 0x7f) { case HP_EVENT: cs_automute(codec); @@ -1585,10 +1584,7 @@ static void init_cs421x_digital(struct hda_codec *codec) if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | SPDIF_EVENT); + snd_hda_jack_detect_enable(codec, nid, SPDIF_EVENT); spec->spdif_detect = 1; } } @@ -1806,6 +1802,8 @@ static int cs421x_build_controls(struct hda_codec *codec) static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) { + snd_hda_jack_set_dirty_all(codec); /* FIXME: to be more fine-grained */ + switch ((res >> 26) & 0x3f) { case HP_EVENT: case SPDIF_EVENT: diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 0de21193a2b0..220e567ccfff 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -31,6 +31,7 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_beep.h" +#include "hda_jack.h" #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -3756,6 +3757,7 @@ static void cx_auto_automic(struct hda_codec *codec) static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) { int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; + snd_hda_jack_set_dirty(codec, nid); switch (res >> 26) { case CONEXANT_HP_EVENT: cx_auto_hp_automute(codec); @@ -3983,9 +3985,7 @@ static void enable_unsol_pins(struct hda_codec *codec, int num_pins, { int i; for (i = 0; i < num_pins; i++) - snd_hda_codec_write(codec, pins[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | tag); + snd_hda_jack_detect_enable(codec, pins[i], tag); } static void cx_auto_init_output(struct hda_codec *codec) @@ -4060,16 +4060,14 @@ static void cx_auto_init_input(struct hda_codec *codec) if (spec->auto_mic) { if (spec->auto_mic_ext >= 0) { - snd_hda_codec_write(codec, - cfg->inputs[spec->auto_mic_ext].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_MIC_EVENT); + snd_hda_jack_detect_enable(codec, + cfg->inputs[spec->auto_mic_ext].pin, + CONEXANT_MIC_EVENT); } if (spec->auto_mic_dock >= 0) { - snd_hda_codec_write(codec, - cfg->inputs[spec->auto_mic_dock].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_MIC_EVENT); + snd_hda_jack_detect_enable(codec, + cfg->inputs[spec->auto_mic_dock].pin, + CONEXANT_MIC_EVENT); } cx_auto_automic(codec); } else { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 9850c5b481ea..ea6d85d48444 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -36,6 +36,7 @@ #include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_jack.h" static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); @@ -766,6 +767,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) if (pin_idx < 0) return; + snd_hda_jack_set_dirty(codec, pin_nid); hdmi_present_sense(&spec->pins[pin_idx], true); } @@ -1282,9 +1284,7 @@ static int generic_hdmi_init(struct hda_codec *codec) struct hdmi_eld *eld = &per_pin->sink_eld; hdmi_init_pin(codec, pin_nid); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | pin_nid); + snd_hda_jack_detect_enable(codec, pin_nid, pin_nid); per_pin->codec = codec; INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 14feecf2d802..da9d2276e68b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -33,6 +33,7 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_beep.h" +#include "hda_jack.h" /* unsol event tags */ #define ALC_FRONT_EVENT 0x01 @@ -664,6 +665,7 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) res >>= 28; else res >>= 26; + snd_hda_jack_set_dirty_all(codec); /* FIXME: to be more fine-grained */ switch (res) { case ALC_HP_EVENT: alc_hp_automute(codec); @@ -964,9 +966,7 @@ static void alc_init_automute(struct hda_codec *codec) continue; snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", nid); - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_HP_EVENT); + snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT); spec->detect_hp = 1; } @@ -978,9 +978,8 @@ static void alc_init_automute(struct hda_codec *codec) continue; snd_printdd("realtek: Enable Line-Out " "auto-muting on NID 0x%x\n", nid); - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_FRONT_EVENT); + snd_hda_jack_detect_enable(codec, nid, + ALC_FRONT_EVENT); spec->detect_lo = 1; } spec->automute_lo_possible = spec->detect_hp; @@ -1108,13 +1107,10 @@ static bool alc_auto_mic_check_imux(struct hda_codec *codec) return false; /* no corresponding imux */ } - snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_MIC_EVENT); + snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT); if (spec->dock_mic_pin) - snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_MIC_EVENT); + snd_hda_jack_detect_enable(codec, spec->dock_mic_pin, + ALC_MIC_EVENT); spec->auto_mic_valid_imux = 1; spec->auto_mic = 1; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3b4ef0cba0e7..97c6df9db5e9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -37,6 +37,7 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_beep.h" +#include "hda_jack.h" enum { STAC_VREF_EVENT = 1, @@ -4244,9 +4245,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, if (tag < 0) return 0; } - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | tag); + snd_hda_jack_detect_enable(codec, nid, tag); return 1; } @@ -4795,24 +4794,11 @@ static void stac92xx_mic_detect(struct hda_codec *codec) mic->mux_idx); } -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_event *event = stac_get_event(codec, nid); - if (!event) - return; - codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); -} - -static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) +static void handle_unsol_event(struct hda_codec *codec, + struct sigmatel_event *event) { struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *event; - int tag, data; - - tag = (res >> 26) & 0x7f; - event = stac_get_event_from_tag(codec, tag); - if (!event) - return; + int data; switch (event->type) { case STAC_HP_EVENT: @@ -4862,6 +4848,28 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_event *event = stac_get_event(codec, nid); + if (!event) + return; + handle_unsol_event(codec, event); +} + +static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_event *event; + int tag; + + tag = (res >> 26) & 0x7f; + event = stac_get_event_from_tag(codec, tag); + if (!event) + return; + snd_hda_jack_set_dirty(codec, event->nid); + handle_unsol_event(codec, event); +} + static int hp_blike_system(u32 subsystem_id); static void set_hp_led_gpio(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 431c0d417eeb..3467d0c23fe9 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -54,6 +54,7 @@ #include <sound/asoundef.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_jack.h" /* Pin Widget NID */ #define VT1708_HP_PIN_NID 0x20 @@ -1708,6 +1709,8 @@ static void via_gpio_control(struct hda_codec *codec) static void via_unsol_event(struct hda_codec *codec, unsigned int res) { + snd_hda_jack_set_dirty_all(codec); /* FIXME: to be more fine-grained */ + res >>= 26; if (res & VIA_JACK_EVENT) @@ -2729,9 +2732,8 @@ static void via_auto_init_unsol_event(struct hda_codec *codec) int i; if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_codec_write(codec, cfg->hp_pins[0], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT); + snd_hda_jack_detect_enable(codec, cfg->hp_pins[0], + VIA_HP_EVENT | VIA_JACK_EVENT); if (cfg->speaker_pins[0]) ev = VIA_LINE_EVENT; @@ -2740,16 +2742,14 @@ static void via_auto_init_unsol_event(struct hda_codec *codec) for (i = 0; i < cfg->line_outs; i++) { if (cfg->line_out_pins[i] && is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ev | VIA_JACK_EVENT); + snd_hda_jack_detect_enable(codec, cfg->line_out_pins[i], + ev | VIA_JACK_EVENT); } for (i = 0; i < cfg->num_inputs; i++) { if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | VIA_JACK_EVENT); + snd_hda_jack_detect_enable(codec, cfg->inputs[i].pin, + VIA_JACK_EVENT); } } @@ -2781,6 +2781,7 @@ static void vt1708_update_hp_jack_state(struct work_struct *work) vt1708_hp_work.work); if (spec->codec_type != VT1708) return; + snd_hda_jack_set_dirty_all(spec->codec); /* if jack state toggled */ if (spec->vt1708_hp_present != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { -- cgit v1.2.3 From aad37dbd563010252e1bedb6dad6cddb867b9235 Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Wed, 2 Nov 2011 08:54:51 +0100 Subject: ALSA: hda - Merge input-jack helpers to hda_jack.c We can use the very same table in hda_jack.c for managing the list for input-jack elements, too. Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_codec.c | 108 ----------------------------------------- sound/pci/hda/hda_jack.c | 97 +++++++++++++++++++++++++++++++++++- sound/pci/hda/hda_jack.h | 4 ++ sound/pci/hda/hda_local.h | 4 -- sound/pci/hda/patch_conexant.c | 1 - sound/pci/hda/patch_hdmi.c | 1 - sound/pci/hda/patch_realtek.c | 1 - sound/pci/hda/patch_sigmatel.c | 1 - 8 files changed, 100 insertions(+), 117 deletions(-) (limited to 'sound/pci/hda/hda_codec.c') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8217ff7ff7b5..e57698f611ab 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5275,113 +5275,5 @@ 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_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_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"); diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a2ab52b27265..1389958b201d 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <sound/core.h> #include <sound/control.h> +#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_jack.h" @@ -87,8 +88,15 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) return jack; } +#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); snd_array_free(&codec->jacktbl); } @@ -186,7 +194,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) if (jack->nid) { jack_detect_update(codec, jack); state = get_jack_plug_state(jack->pin_sense); - snd_kctl_jack_notify(codec->bus->card, jack->kctl, state); + snd_kctl_jack_report(codec->bus->card, jack->kctl, state); } } EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync); @@ -287,3 +295,90 @@ 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->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) + 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 */ diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 4bb75ee16b56..f8f97c71c9c1 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -22,6 +22,10 @@ struct hda_jack_tbl { unsigned int jack_detect:1; /* capable of jack-detection? */ unsigned int jack_dirty:1; /* needs to update? */ struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ +#ifdef CONFIG_SND_HDA_INPUT_JACK + int type; + struct snd_jack *jack; +#endif }; struct hda_jack_tbl * diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 08e88b826d27..13f681480a38 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -680,7 +680,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); 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, @@ -692,9 +691,6 @@ 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 */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 40bd75b293ba..ae9c028d8254 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -475,7 +475,6 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { - snd_hda_input_jack_free(codec); snd_hda_detach_beep_device(codec); kfree(codec->spec); } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ea30bf4a4f50..bb8cfc68cd73 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1318,7 +1318,6 @@ static void generic_hdmi_free(struct hda_codec *codec) cancel_delayed_work(&per_pin->work); snd_hda_eld_proc_free(codec, eld); } - snd_hda_input_jack_free(codec); flush_workqueue(codec->bus->workq); kfree(spec); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a90cdac78f4..933c8cf23b27 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2474,7 +2474,6 @@ static void alc_free(struct hda_codec *codec) return; alc_shutup(codec); - snd_hda_input_jack_free(codec); alc_free_kctls(codec); alc_free_bind_ctls(codec); kfree(spec); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index dd6569ffcff8..73bf7cd0a6e4 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4489,7 +4489,6 @@ static void stac92xx_free(struct hda_codec *codec) return; stac92xx_shutup(codec); - snd_hda_input_jack_free(codec); kfree(spec); snd_hda_detach_beep_device(codec); -- cgit v1.2.3 From 201e06ffa9ef9b5265e636617f4fa20cd1490343 Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Wed, 16 Nov 2011 15:33:26 +0100 Subject: ALSA: hda - Give more unique names by snd_hda_get_pin_label() The function now gives more unique names for the output pins by adding some prefix and suffix for the location and the channels. Otherwise, it can pass the index number. Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_codec.c | 141 +++++++++++++++++++++++++++++++---------- sound/pci/hda/hda_jack.c | 24 +++---- sound/pci/hda/hda_local.h | 5 +- sound/pci/hda/patch_ca0110.c | 6 +- sound/pci/hda/patch_cirrus.c | 5 +- sound/pci/hda/patch_sigmatel.c | 8 ++- 6 files changed, 135 insertions(+), 54 deletions(-) (limited to 'sound/pci/hda/hda_codec.c') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e57698f611ab..e050f893bf75 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5066,61 +5066,136 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); +/* get a unique suffix or an index number */ +static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, + int num_pins, int *indexp) +{ + static const char * const channel_sfx[] = { + " Front", " Surrount", " CLFE", " Side" + }; + int i; + + for (i = 0; i < num_pins; i++) { + if (pins[i] == nid) { + if (num_pins == 1) + return ""; + if (num_pins > ARRAY_SIZE(channel_sfx)) { + if (indexp) + *indexp = i; + return ""; + } + return channel_sfx[i]; + } + } + return NULL; +} + +static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg, + const char *name, char *label, int maxlen, + int *indexp) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int attr = snd_hda_get_input_pin_attr(def_conf); + const char *pfx = "", *sfx = ""; + + /* handle as a speaker if it's a fixed line-out */ + if (!strcmp(name, "Line-Out") && attr == INPUT_PIN_ATTR_INT) + name = "Speaker"; + /* check the location */ + switch (attr) { + case INPUT_PIN_ATTR_DOCK: + pfx = "Dock "; + break; + case INPUT_PIN_ATTR_FRONT: + pfx = "Front "; + break; + } + if (cfg) { + /* try to give a unique suffix if needed */ + sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, + indexp); + if (!sfx) + sfx = check_output_sfx(nid, cfg->hp_pins, cfg->hp_outs, + indexp); + if (!sfx) + sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs, + indexp); + if (!sfx) + sfx = ""; + } + snprintf(label, maxlen, "%s%s%s", pfx, name, sfx); + return 1; +} + /** * snd_hda_get_pin_label - Get a label for the given I/O pin * * Get a label for the given pin. This function works for both input and * output pins. When @cfg is given as non-NULL, the function tries to get * an optimized label using hda_get_autocfg_input_label(). + * + * This function tries to give a unique label string for the pin as much as + * possible. For example, when the multiple line-outs are present, it adds + * the channel suffix like "Front", "Surround", etc (only when @cfg is given). + * If no unique name with a suffix is available and @indexp is non-NULL, the + * index number is stored in the pointer. */ -const char *snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg) +int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg, + char *label, int maxlen, int *indexp) { unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int attr; + const char *name = NULL; int i; + if (indexp) + *indexp = 0; if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - return NULL; + return 0; - attr = snd_hda_get_input_pin_attr(def_conf); switch (get_defcfg_device(def_conf)) { case AC_JACK_LINE_OUT: - switch (attr) { - case INPUT_PIN_ATTR_INT: - return "Speaker"; - case INPUT_PIN_ATTR_DOCK: - return "Dock Line-Out"; - case INPUT_PIN_ATTR_FRONT: - return "Front Line-Out"; - default: - return "Line-Out"; - } + return fill_audio_out_name(codec, nid, cfg, "Line-Out", + label, maxlen, indexp); case AC_JACK_SPEAKER: - return "Speaker"; + return fill_audio_out_name(codec, nid, cfg, "Speaker", + label, maxlen, indexp); case AC_JACK_HP_OUT: - switch (attr) { - case INPUT_PIN_ATTR_DOCK: - return "Dock Headphone"; - case INPUT_PIN_ATTR_FRONT: - return "Front Headphone"; - default: - return "Headphone"; - } + return fill_audio_out_name(codec, nid, cfg, "Headphone", + label, maxlen, indexp); case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI) - return "HDMI"; + name = "HDMI"; else - return "SPDIF"; - } - - if (cfg) { - for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].pin == nid) - return hda_get_autocfg_input_label(codec, cfg, i); + name = "SPDIF"; + if (cfg && indexp) { + for (i = 0; i < cfg->dig_outs; i++) + if (cfg->dig_out_pins[i] == nid) { + *indexp = i; + break; + } + } + break; + default: + if (cfg) { + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].pin != nid) + continue; + name = hda_get_autocfg_input_label(codec, cfg, i); + if (name) + break; + } + } + if (!name) + name = hda_get_input_pin_label(codec, nid, true); + break; } - return hda_get_input_pin_label(codec, nid, true); + if (!name) + return 0; + strlcpy(label, name, maxlen); + return 1; } EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 25f756533bec..394901515d9e 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -232,11 +232,12 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); -static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int idx, +static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const struct auto_pin_cfg *cfg) { unsigned int def_conf, conn; - int err; + char name[44]; + int idx, err; if (!nid) return 0; @@ -247,9 +248,8 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int idx, if (conn != AC_JACK_PORT_COMPLEX) return 0; - err = snd_hda_jack_add_kctl(codec, nid, - snd_hda_get_pin_label(codec, nid, cfg), - idx); + snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); + err = snd_hda_jack_add_kctl(codec, nid, name, idx); if (err < 0) return err; return snd_hda_jack_detect_enable(codec, nid, 0); @@ -265,38 +265,38 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, int i, err; for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { - err = add_jack_kctl(codec, *p, i, cfg); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, i, cfg); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, i, cfg); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } for (i = 0; i < cfg->num_inputs; i++) { - err = add_jack_kctl(codec, cfg->inputs[i].pin, 0, cfg); + err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg); if (err < 0) return err; } for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { - err = add_jack_kctl(codec, *p, i, cfg); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } - err = add_jack_kctl(codec, cfg->dig_in_pin, 0, cfg); + err = add_jack_kctl(codec, cfg->dig_in_pin, cfg); if (err < 0) return err; - err = add_jack_kctl(codec, cfg->mono_out_pin, 0, cfg); + err = add_jack_kctl(codec, cfg->mono_out_pin, cfg); if (err < 0) return err; return 0; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 13f681480a38..ef09716aeb6f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -397,8 +397,9 @@ struct auto_pin_cfg; const char *hda_get_autocfg_input_label(struct hda_codec *codec, const struct auto_pin_cfg *cfg, int input); -const char *snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg); +int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg, + char *label, int maxlen, int *indexp); int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, int index, int *type_index_ret); diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 6bd602bfe0fe..09ccfabb4a17 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -41,7 +41,7 @@ struct ca0110_spec { hda_nid_t dig_out; hda_nid_t dig_in; unsigned int num_inputs; - const char *input_labels[AUTO_PIN_LAST]; + char input_labels[AUTO_PIN_LAST][32]; struct hda_pcm pcm_rec[2]; /* PCM information */ }; @@ -476,7 +476,9 @@ static void parse_input(struct hda_codec *codec) if (j >= cfg->num_inputs) continue; spec->input_pins[n] = pin; - spec->input_labels[n] = snd_hda_get_pin_label(codec, pin, NULL); + snd_hda_get_pin_label(codec, pin, cfg, + spec->input_labels[n], + sizeof(spec->input_labels[n]), NULL); spec->adcs[n] = nid; n++; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 0e34554bc45e..0ba03878c5e0 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -711,8 +711,9 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= spec->num_inputs) uinfo->value.enumerated.item = spec->num_inputs - 1; idx = spec->input_idx[uinfo->value.enumerated.item]; - strcpy(uinfo->value.enumerated.name, - snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, NULL)); + snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, cfg, + uinfo->value.enumerated.name, + sizeof(uinfo->value.enumerated.name), NULL); return 0; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 73bf7cd0a6e4..0988dc4890a1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2867,7 +2867,8 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, } if (control) { - strcpy(name, snd_hda_get_pin_label(codec, nid, NULL)); + snd_hda_get_pin_label(codec, nid, &spec->autocfg, + name, sizeof(name), NULL); return stac92xx_add_control(codec->spec, control, strcat(name, " Jack Mode"), nid); } @@ -3545,7 +3546,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; int index, type_idx; - const char *label; + char label[32]; nid = spec->dmic_nids[i]; if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) @@ -3558,7 +3559,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, if (index < 0) continue; - label = snd_hda_get_pin_label(codec, nid, NULL); + snd_hda_get_pin_label(codec, nid, &spec->autocfg, + label, sizeof(label), NULL); snd_hda_add_imux_item(dimux, label, index, &type_idx); if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) snd_hda_add_imux_item(imux, label, index, &type_idx); -- cgit v1.2.3 From d6018bb566f6eef277184278b105e04705e8aeb6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Mon, 21 Nov 2011 14:17:16 +0100 Subject: ALSA: hda - Fix a typo Reported-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda/hda_codec.c') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e050f893bf75..b703e25b6241 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5071,7 +5071,7 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, int num_pins, int *indexp) { static const char * const channel_sfx[] = { - " Front", " Surrount", " CLFE", " Side" + " Front", " Surround", " CLFE", " Side" }; int i; -- cgit v1.2.3 From 358b6e62b86f6313d114e0f6b7d8f8adaf85ed9c Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Mon, 21 Nov 2011 14:34:20 +0100 Subject: ALSA: hda - Don't add channel suffix for headphone pin labels The multiple headphone pins are usually handled as copied from the same source, not as individual channels like front and surround. Thus it'd be more correct to avoid the channel suffix for "Headphone" pin labels in snd_hda_get_pin_label() but give an index number instead. Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_codec.c | 52 ++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) (limited to 'sound/pci/hda/hda_codec.c') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b703e25b6241..de3325e79087 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5066,6 +5066,16 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} + /* get a unique suffix or an index number */ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, int num_pins, int *indexp) @@ -5075,19 +5085,17 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, }; int i; - for (i = 0; i < num_pins; i++) { - if (pins[i] == nid) { - if (num_pins == 1) - return ""; - if (num_pins > ARRAY_SIZE(channel_sfx)) { - if (indexp) - *indexp = i; - return ""; - } - return channel_sfx[i]; - } + i = find_idx_in_nid_list(nid, pins, num_pins); + if (i < 0) + return NULL; + if (num_pins == 1) + return ""; + if (num_pins > ARRAY_SIZE(channel_sfx)) { + if (indexp) + *indexp = i; + return ""; } - return NULL; + return channel_sfx[i]; } static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, @@ -5115,14 +5123,17 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, /* try to give a unique suffix if needed */ sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, indexp); - if (!sfx) - sfx = check_output_sfx(nid, cfg->hp_pins, cfg->hp_outs, - indexp); if (!sfx) sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs, indexp); - if (!sfx) + if (!sfx) { + /* don't add channel suffix for Headphone controls */ + int idx = find_idx_in_nid_list(nid, cfg->hp_pins, + cfg->hp_outs); + if (idx >= 0) + *indexp = idx; sfx = ""; + } } snprintf(label, maxlen, "%s%s%s", pfx, name, sfx); return 1; @@ -5171,11 +5182,10 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, else name = "SPDIF"; if (cfg && indexp) { - for (i = 0; i < cfg->dig_outs; i++) - if (cfg->dig_out_pins[i] == nid) { - *indexp = i; - break; - } + i = find_idx_in_nid_list(nid, cfg->dig_out_pins, + cfg->dig_outs); + if (i >= 0) + *indexp = i; } break; default: -- cgit v1.2.3