diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-05-07 17:42:31 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-05-08 18:01:33 +0200 |
commit | 128bc4ba8c52194eae5a80594ec9b7f6b35ba88f (patch) | |
tree | 02cf180917b5a5f6732eaa5f6bfebd91abc120d8 | |
parent | ALSA: hda - Move up the fixup helper functions to the library module (diff) | |
download | linux-128bc4ba8c52194eae5a80594ec9b7f6b35ba88f.tar.xz linux-128bc4ba8c52194eae5a80594ec9b7f6b35ba88f.zip |
ALSA: hda - Move BIOS pin-parser code to hda_auto_parser.c
Just code shuffles.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/hda_auto_parser.c | 597 | ||||
-rw-r--r-- | sound/pci/hda/hda_auto_parser.h | 80 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 596 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 82 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_ca0110.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_ca0132.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 1 |
13 files changed, 690 insertions, 675 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7cc3a1688240..6e9ef3e25093 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -13,10 +13,607 @@ #include <linux/export.h> #include <sound/core.h> #include "hda_codec.h" +#include "hda_local.h" #include "hda_auto_parser.h" #define SFX "hda_codec: " +/* + * Helper for automatic pin configuration + */ + +static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) +{ + for (; *list; list++) + if (*list == nid) + return 1; + return 0; +} + + +/* + * Sort an associated group of pins according to their sequence numbers. + */ +static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, + int num_pins) +{ + int i, j; + short seq; + hda_nid_t nid; + + for (i = 0; i < num_pins; i++) { + for (j = i + 1; j < num_pins; j++) { + if (sequences[i] > sequences[j]) { + seq = sequences[i]; + sequences[i] = sequences[j]; + sequences[j] = seq; + nid = pins[i]; + pins[i] = pins[j]; + pins[j] = nid; + } + } + } +} + + +/* add the found input-pin to the cfg->inputs[] table */ +static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, + int type) +{ + if (cfg->num_inputs < AUTO_CFG_MAX_INS) { + cfg->inputs[cfg->num_inputs].pin = nid; + cfg->inputs[cfg->num_inputs].type = type; + cfg->num_inputs++; + } +} + +/* sort inputs in the order of AUTO_PIN_* type */ +static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) +{ + int i, j; + + for (i = 0; i < cfg->num_inputs; i++) { + for (j = i + 1; j < cfg->num_inputs; j++) { + if (cfg->inputs[i].type > cfg->inputs[j].type) { + struct auto_pin_cfg_item tmp; + tmp = cfg->inputs[i]; + cfg->inputs[i] = cfg->inputs[j]; + cfg->inputs[j] = tmp; + } + } + } +} + +/* Reorder the surround channels + * ALSA sequence is front/surr/clfe/side + * HDA sequence is: + * 4-ch: front/surr => OK as it is + * 6-ch: front/clfe/surr + * 8-ch: front/clfe/rear/side|fc + */ +static void reorder_outputs(unsigned int nums, hda_nid_t *pins) +{ + hda_nid_t nid; + + switch (nums) { + case 3: + case 4: + nid = pins[1]; + pins[1] = pins[2]; + pins[2] = nid; + break; + } +} + +/* + * Parse all pin widgets and store the useful pin nids to cfg + * + * The number of line-outs or any primary output is stored in line_outs, + * and the corresponding output pins are assigned to line_out_pins[], + * in the order of front, rear, CLFE, side, ... + * + * If more extra outputs (speaker and headphone) are found, the pins are + * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack + * is detected, one of speaker of HP pins is assigned as the primary + * output, i.e. to line_out_pins[0]. So, line_outs is always positive + * if any analog output exists. + * + * The analog input pins are assigned to inputs array. + * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, + * respectively. + */ +int snd_hda_parse_pin_defcfg(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + const hda_nid_t *ignore_nids, + unsigned int cond_flags) +{ + hda_nid_t nid, end_nid; + short seq, assoc_line_out; + short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; + short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; + short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; + int i; + + memset(cfg, 0, sizeof(*cfg)); + + memset(sequences_line_out, 0, sizeof(sequences_line_out)); + memset(sequences_speaker, 0, sizeof(sequences_speaker)); + memset(sequences_hp, 0, sizeof(sequences_hp)); + assoc_line_out = 0; + + codec->ignore_misc_bit = true; + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wid_caps = get_wcaps(codec, nid); + unsigned int wid_type = get_wcaps_type(wid_caps); + unsigned int def_conf; + short assoc, loc, conn, dev; + + /* read all default configuration for pin complex */ + if (wid_type != AC_WID_PIN) + continue; + /* ignore the given nids (e.g. pc-beep returns error) */ + if (ignore_nids && is_in_nid_list(nid, ignore_nids)) + continue; + + def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE)) + codec->ignore_misc_bit = false; + conn = get_defcfg_connect(def_conf); + if (conn == AC_JACK_PORT_NONE) + continue; + loc = get_defcfg_location(def_conf); + dev = get_defcfg_device(def_conf); + + /* workaround for buggy BIOS setups */ + if (dev == AC_JACK_LINE_OUT) { + if (conn == AC_JACK_PORT_FIXED) + dev = AC_JACK_SPEAKER; + } + + switch (dev) { + case AC_JACK_LINE_OUT: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + + if (!(wid_caps & AC_WCAP_STEREO)) + if (!cfg->mono_out_pin) + cfg->mono_out_pin = nid; + if (!assoc) + continue; + if (!assoc_line_out) + assoc_line_out = assoc; + else if (assoc_line_out != assoc) + continue; + if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) + continue; + cfg->line_out_pins[cfg->line_outs] = nid; + sequences_line_out[cfg->line_outs] = seq; + cfg->line_outs++; + break; + case AC_JACK_SPEAKER: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) + continue; + cfg->speaker_pins[cfg->speaker_outs] = nid; + sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; + cfg->speaker_outs++; + break; + case AC_JACK_HP_OUT: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) + continue; + cfg->hp_pins[cfg->hp_outs] = nid; + sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; + cfg->hp_outs++; + break; + case AC_JACK_MIC_IN: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); + break; + case AC_JACK_LINE_IN: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); + break; + case AC_JACK_CD: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); + break; + case AC_JACK_AUX: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); + break; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) + continue; + cfg->dig_out_pins[cfg->dig_outs] = nid; + cfg->dig_out_type[cfg->dig_outs] = + (loc == AC_JACK_LOC_HDMI) ? + HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; + cfg->dig_outs++; + break; + case AC_JACK_SPDIF_IN: + case AC_JACK_DIG_OTHER_IN: + cfg->dig_in_pin = nid; + if (loc == AC_JACK_LOC_HDMI) + cfg->dig_in_type = HDA_PCM_TYPE_HDMI; + else + cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; + break; + } + } + + /* FIX-UP: + * If no line-out is defined but multiple HPs are found, + * some of them might be the real line-outs. + */ + if (!cfg->line_outs && cfg->hp_outs > 1 && + !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { + int i = 0; + while (i < cfg->hp_outs) { + /* The real HPs should have the sequence 0x0f */ + if ((sequences_hp[i] & 0x0f) == 0x0f) { + i++; + continue; + } + /* Move it to the line-out table */ + cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; + sequences_line_out[cfg->line_outs] = sequences_hp[i]; + cfg->line_outs++; + cfg->hp_outs--; + memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, + sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); + memmove(sequences_hp + i, sequences_hp + i + 1, + sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); + } + memset(cfg->hp_pins + cfg->hp_outs, 0, + sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); + if (!cfg->hp_outs) + cfg->line_out_type = AUTO_PIN_HP_OUT; + + } + + /* sort by sequence */ + sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, + cfg->line_outs); + sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, + cfg->speaker_outs); + sort_pins_by_sequence(cfg->hp_pins, sequences_hp, + cfg->hp_outs); + + /* + * FIX-UP: if no line-outs are detected, try to use speaker or HP pin + * as a primary output + */ + if (!cfg->line_outs && + !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { + if (cfg->speaker_outs) { + cfg->line_outs = cfg->speaker_outs; + memcpy(cfg->line_out_pins, cfg->speaker_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = 0; + memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); + cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; + } else if (cfg->hp_outs) { + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + } + } + + reorder_outputs(cfg->line_outs, cfg->line_out_pins); + reorder_outputs(cfg->hp_outs, cfg->hp_pins); + reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); + + sort_autocfg_input_pins(cfg); + + /* + * debug prints of the parsed results + */ + snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", + cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], + cfg->line_out_pins[2], cfg->line_out_pins[3], + cfg->line_out_pins[4], + cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : + (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? + "speaker" : "line")); + snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->speaker_outs, cfg->speaker_pins[0], + cfg->speaker_pins[1], cfg->speaker_pins[2], + cfg->speaker_pins[3], cfg->speaker_pins[4]); + snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->hp_outs, cfg->hp_pins[0], + cfg->hp_pins[1], cfg->hp_pins[2], + cfg->hp_pins[3], cfg->hp_pins[4]); + snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); + if (cfg->dig_outs) + snd_printd(" dig-out=0x%x/0x%x\n", + cfg->dig_out_pins[0], cfg->dig_out_pins[1]); + snd_printd(" inputs:"); + for (i = 0; i < cfg->num_inputs; i++) { + snd_printd(" %s=0x%x", + hda_get_autocfg_input_label(codec, cfg, i), + cfg->inputs[i].pin); + } + snd_printd("\n"); + if (cfg->dig_in_pin) + snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); + + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); + +int snd_hda_get_input_pin_attr(unsigned int def_conf) +{ + unsigned int loc = get_defcfg_location(def_conf); + unsigned int conn = get_defcfg_connect(def_conf); + if (conn == AC_JACK_PORT_NONE) + return INPUT_PIN_ATTR_UNUSED; + /* Windows may claim the internal mic to be BOTH, too */ + if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) + return INPUT_PIN_ATTR_INT; + if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) + return INPUT_PIN_ATTR_INT; + if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) + return INPUT_PIN_ATTR_DOCK; + if (loc == AC_JACK_LOC_REAR) + return INPUT_PIN_ATTR_REAR; + if (loc == AC_JACK_LOC_FRONT) + return INPUT_PIN_ATTR_FRONT; + return INPUT_PIN_ATTR_NORMAL; +} +EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); + +/** + * hda_get_input_pin_label - Give a label for the given input pin + * + * When check_location is true, the function checks the pin location + * for mic and line-in pins, and set an appropriate prefix like "Front", + * "Rear", "Internal". + */ + +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[] = { + "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", + }; + int attr; + + def_conf = snd_hda_codec_get_pincfg(codec, pin); + + switch (get_defcfg_device(def_conf)) { + case AC_JACK_MIC_IN: + if (!check_location) + return "Mic"; + attr = snd_hda_get_input_pin_attr(def_conf); + if (!attr) + return "None"; + return mic_names[attr - 1]; + case AC_JACK_LINE_IN: + if (!check_location) + return "Line"; + attr = snd_hda_get_input_pin_attr(def_conf); + if (!attr) + return "None"; + if (attr == INPUT_PIN_ATTR_DOCK) + return "Dock Line"; + return "Line"; + case AC_JACK_AUX: + return "Aux"; + case AC_JACK_CD: + return "CD"; + case AC_JACK_SPDIF_IN: + return "SPDIF In"; + case AC_JACK_DIG_OTHER_IN: + return "Digital In"; + default: + return "Misc"; + } +} + +/* 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 + * have to put "Front" prefix to each label. In such a case, returns false. + */ +static int check_mic_location_need(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input) +{ + unsigned int defc; + int i, attr, attr2; + + defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); + attr = snd_hda_get_input_pin_attr(defc); + /* for internal or docking mics, we need locations */ + if (attr <= INPUT_PIN_ATTR_NORMAL) + return 1; + + attr = 0; + for (i = 0; i < cfg->num_inputs; i++) { + defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); + attr2 = snd_hda_get_input_pin_attr(defc); + if (attr2 >= INPUT_PIN_ATTR_NORMAL) { + if (attr && attr != attr2) + return 1; /* different locations found */ + attr = attr2; + } + } + return 0; +} + +/** + * hda_get_autocfg_input_label - Get a label for the given input + * + * Get a label for the given input pin defined by the autocfg item. + * Unlike hda_get_input_pin_label(), this function checks all inputs + * defined in autocfg and avoids the redundant mic/line prefix as much as + * possible. + */ +const char *hda_get_autocfg_input_label(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input) +{ + int type = cfg->inputs[input].type; + int has_multiple_pins = 0; + + if ((input > 0 && cfg->inputs[input - 1].type == type) || + (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) + has_multiple_pins = 1; + if (has_multiple_pins && type == AUTO_PIN_MIC) + has_multiple_pins &= check_mic_location_need(codec, cfg, input); + return hda_get_input_pin_label(codec, cfg->inputs[input].pin, + has_multiple_pins); +} +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) +{ + static const char * const channel_sfx[] = { + " Front", " Surround", " CLFE", " Side" + }; + int 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 channel_sfx[i]; +} + +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->speaker_pins, cfg->speaker_outs, + indexp); + 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; +} + +/** + * 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. + */ +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); + const char *name = NULL; + int i; + + if (indexp) + *indexp = 0; + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + return 0; + + switch (get_defcfg_device(def_conf)) { + case AC_JACK_LINE_OUT: + return fill_audio_out_name(codec, nid, cfg, "Line Out", + label, maxlen, indexp); + case AC_JACK_SPEAKER: + return fill_audio_out_name(codec, nid, cfg, "Speaker", + label, maxlen, indexp); + case AC_JACK_HP_OUT: + 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) + name = "HDMI"; + else + name = "SPDIF"; + if (cfg && indexp) { + i = find_idx_in_nid_list(nid, cfg->dig_out_pins, + cfg->dig_outs); + if (i >= 0) + *indexp = i; + } + 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; + } + if (!name) + return 0; + strlcpy(label, name, maxlen); + return 1; +} +EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); + int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, const struct hda_verb *list) { diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index 9fe4f5d245ad..2a7889dfbd1b 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -12,6 +12,86 @@ #ifndef __SOUND_HDA_AUTO_PARSER_H #define __SOUND_HDA_AUTO_PARSER_H +/* + * Helper for automatic pin configuration + */ + +enum { + AUTO_PIN_MIC, + AUTO_PIN_LINE_IN, + AUTO_PIN_CD, + AUTO_PIN_AUX, + AUTO_PIN_LAST +}; + +enum { + AUTO_PIN_LINE_OUT, + AUTO_PIN_SPEAKER_OUT, + AUTO_PIN_HP_OUT +}; + +#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS +#define AUTO_CFG_MAX_INS 8 + +struct auto_pin_cfg_item { + hda_nid_t pin; + int type; +}; + +struct auto_pin_cfg; +const char *hda_get_autocfg_input_label(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input); +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); + +enum { + INPUT_PIN_ATTR_UNUSED, /* pin not connected */ + INPUT_PIN_ATTR_INT, /* internal mic/line-in */ + INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ + INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ + INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ + INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ +}; + +int snd_hda_get_input_pin_attr(unsigned int def_conf); + +struct auto_pin_cfg { + int line_outs; + /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS]; + int speaker_outs; + hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS]; + int hp_outs; + int line_out_type; /* AUTO_PIN_XXX_OUT */ + hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; + int num_inputs; + struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS]; + int dig_outs; + hda_nid_t dig_out_pins[2]; + hda_nid_t dig_in_pin; + hda_nid_t mono_out_pin; + int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */ + int dig_in_type; /* HDA_PCM_TYPE_XXX */ +}; + +/* bit-flags for snd_hda_parse_pin_def_config() behavior */ +#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ +#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ + +int snd_hda_parse_pin_defcfg(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + const hda_nid_t *ignore_nids, + unsigned int cond_flags); + +/* older function */ +#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ + snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) + +/* + */ + struct hda_gen_spec { /* fix-up list */ int fixup_id; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 30a3d8ff978b..f2bdf38be395 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4877,602 +4877,6 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, } EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl); -/* - * Helper for automatic pin configuration - */ - -static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) -{ - for (; *list; list++) - if (*list == nid) - return 1; - return 0; -} - - -/* - * Sort an associated group of pins according to their sequence numbers. - */ -static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, - int num_pins) -{ - int i, j; - short seq; - hda_nid_t nid; - - for (i = 0; i < num_pins; i++) { - for (j = i + 1; j < num_pins; j++) { - if (sequences[i] > sequences[j]) { - seq = sequences[i]; - sequences[i] = sequences[j]; - sequences[j] = seq; - nid = pins[i]; - pins[i] = pins[j]; - pins[j] = nid; - } - } - } -} - - -/* add the found input-pin to the cfg->inputs[] table */ -static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, - int type) -{ - if (cfg->num_inputs < AUTO_CFG_MAX_INS) { - cfg->inputs[cfg->num_inputs].pin = nid; - cfg->inputs[cfg->num_inputs].type = type; - cfg->num_inputs++; - } -} - -/* sort inputs in the order of AUTO_PIN_* type */ -static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) -{ - int i, j; - - for (i = 0; i < cfg->num_inputs; i++) { - for (j = i + 1; j < cfg->num_inputs; j++) { - if (cfg->inputs[i].type > cfg->inputs[j].type) { - struct auto_pin_cfg_item tmp; - tmp = cfg->inputs[i]; - cfg->inputs[i] = cfg->inputs[j]; - cfg->inputs[j] = tmp; - } - } - } -} - -/* Reorder the surround channels - * ALSA sequence is front/surr/clfe/side - * HDA sequence is: - * 4-ch: front/surr => OK as it is - * 6-ch: front/clfe/surr - * 8-ch: front/clfe/rear/side|fc - */ -static void reorder_outputs(unsigned int nums, hda_nid_t *pins) -{ - hda_nid_t nid; - - switch (nums) { - case 3: - case 4: - nid = pins[1]; - pins[1] = pins[2]; - pins[2] = nid; - break; - } -} - -/* - * Parse all pin widgets and store the useful pin nids to cfg - * - * The number of line-outs or any primary output is stored in line_outs, - * and the corresponding output pins are assigned to line_out_pins[], - * in the order of front, rear, CLFE, side, ... - * - * If more extra outputs (speaker and headphone) are found, the pins are - * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack - * is detected, one of speaker of HP pins is assigned as the primary - * output, i.e. to line_out_pins[0]. So, line_outs is always positive - * if any analog output exists. - * - * The analog input pins are assigned to inputs array. - * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, - * respectively. - */ -int snd_hda_parse_pin_defcfg(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids, - unsigned int cond_flags) -{ - hda_nid_t nid, end_nid; - short seq, assoc_line_out; - short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; - short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; - short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; - int i; - - memset(cfg, 0, sizeof(*cfg)); - - memset(sequences_line_out, 0, sizeof(sequences_line_out)); - memset(sequences_speaker, 0, sizeof(sequences_speaker)); - memset(sequences_hp, 0, sizeof(sequences_hp)); - assoc_line_out = 0; - - codec->ignore_misc_bit = true; - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wid_caps = get_wcaps(codec, nid); - unsigned int wid_type = get_wcaps_type(wid_caps); - unsigned int def_conf; - short assoc, loc, conn, dev; - - /* read all default configuration for pin complex */ - if (wid_type != AC_WID_PIN) - continue; - /* ignore the given nids (e.g. pc-beep returns error) */ - if (ignore_nids && is_in_nid_list(nid, ignore_nids)) - continue; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) - codec->ignore_misc_bit = false; - conn = get_defcfg_connect(def_conf); - if (conn == AC_JACK_PORT_NONE) - continue; - loc = get_defcfg_location(def_conf); - dev = get_defcfg_device(def_conf); - - /* workaround for buggy BIOS setups */ - if (dev == AC_JACK_LINE_OUT) { - if (conn == AC_JACK_PORT_FIXED) - dev = AC_JACK_SPEAKER; - } - - switch (dev) { - case AC_JACK_LINE_OUT: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - - if (!(wid_caps & AC_WCAP_STEREO)) - if (!cfg->mono_out_pin) - cfg->mono_out_pin = nid; - if (!assoc) - continue; - if (!assoc_line_out) - assoc_line_out = assoc; - else if (assoc_line_out != assoc) - continue; - if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) - continue; - cfg->line_out_pins[cfg->line_outs] = nid; - sequences_line_out[cfg->line_outs] = seq; - cfg->line_outs++; - break; - case AC_JACK_SPEAKER: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) - continue; - cfg->speaker_pins[cfg->speaker_outs] = nid; - sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; - cfg->speaker_outs++; - break; - case AC_JACK_HP_OUT: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) - continue; - cfg->hp_pins[cfg->hp_outs] = nid; - sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; - cfg->hp_outs++; - break; - case AC_JACK_MIC_IN: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); - break; - case AC_JACK_LINE_IN: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); - break; - case AC_JACK_CD: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); - break; - case AC_JACK_AUX: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); - break; - case AC_JACK_SPDIF_OUT: - case AC_JACK_DIG_OTHER_OUT: - if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) - continue; - cfg->dig_out_pins[cfg->dig_outs] = nid; - cfg->dig_out_type[cfg->dig_outs] = - (loc == AC_JACK_LOC_HDMI) ? - HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; - cfg->dig_outs++; - break; - case AC_JACK_SPDIF_IN: - case AC_JACK_DIG_OTHER_IN: - cfg->dig_in_pin = nid; - if (loc == AC_JACK_LOC_HDMI) - cfg->dig_in_type = HDA_PCM_TYPE_HDMI; - else - cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; - break; - } - } - - /* FIX-UP: - * If no line-out is defined but multiple HPs are found, - * some of them might be the real line-outs. - */ - if (!cfg->line_outs && cfg->hp_outs > 1 && - !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { - int i = 0; - while (i < cfg->hp_outs) { - /* The real HPs should have the sequence 0x0f */ - if ((sequences_hp[i] & 0x0f) == 0x0f) { - i++; - continue; - } - /* Move it to the line-out table */ - cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; - sequences_line_out[cfg->line_outs] = sequences_hp[i]; - cfg->line_outs++; - cfg->hp_outs--; - memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, - sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); - memmove(sequences_hp + i, sequences_hp + i + 1, - sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); - } - memset(cfg->hp_pins + cfg->hp_outs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); - if (!cfg->hp_outs) - cfg->line_out_type = AUTO_PIN_HP_OUT; - - } - - /* sort by sequence */ - sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, - cfg->line_outs); - sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, - cfg->speaker_outs); - sort_pins_by_sequence(cfg->hp_pins, sequences_hp, - cfg->hp_outs); - - /* - * FIX-UP: if no line-outs are detected, try to use speaker or HP pin - * as a primary output - */ - if (!cfg->line_outs && - !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { - if (cfg->speaker_outs) { - cfg->line_outs = cfg->speaker_outs; - memcpy(cfg->line_out_pins, cfg->speaker_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = 0; - memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); - cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; - } else if (cfg->hp_outs) { - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - } - } - - reorder_outputs(cfg->line_outs, cfg->line_out_pins); - reorder_outputs(cfg->hp_outs, cfg->hp_pins); - reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); - - sort_autocfg_input_pins(cfg); - - /* - * debug prints of the parsed results - */ - snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", - cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[3], - cfg->line_out_pins[4], - cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : - (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? - "speaker" : "line")); - snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - cfg->speaker_outs, cfg->speaker_pins[0], - cfg->speaker_pins[1], cfg->speaker_pins[2], - cfg->speaker_pins[3], cfg->speaker_pins[4]); - snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - cfg->hp_outs, cfg->hp_pins[0], - cfg->hp_pins[1], cfg->hp_pins[2], - cfg->hp_pins[3], cfg->hp_pins[4]); - snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); - if (cfg->dig_outs) - snd_printd(" dig-out=0x%x/0x%x\n", - cfg->dig_out_pins[0], cfg->dig_out_pins[1]); - snd_printd(" inputs:"); - for (i = 0; i < cfg->num_inputs; i++) { - snd_printd(" %s=0x%x", - hda_get_autocfg_input_label(codec, cfg, i), - cfg->inputs[i].pin); - } - snd_printd("\n"); - if (cfg->dig_in_pin) - snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); - - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); - -int snd_hda_get_input_pin_attr(unsigned int def_conf) -{ - unsigned int loc = get_defcfg_location(def_conf); - unsigned int conn = get_defcfg_connect(def_conf); - if (conn == AC_JACK_PORT_NONE) - return INPUT_PIN_ATTR_UNUSED; - /* Windows may claim the internal mic to be BOTH, too */ - if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) - return INPUT_PIN_ATTR_INT; - if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) - return INPUT_PIN_ATTR_INT; - if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) - return INPUT_PIN_ATTR_DOCK; - if (loc == AC_JACK_LOC_REAR) - return INPUT_PIN_ATTR_REAR; - if (loc == AC_JACK_LOC_FRONT) - return INPUT_PIN_ATTR_FRONT; - return INPUT_PIN_ATTR_NORMAL; -} -EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); - -/** - * hda_get_input_pin_label - Give a label for the given input pin - * - * When check_location is true, the function checks the pin location - * for mic and line-in pins, and set an appropriate prefix like "Front", - * "Rear", "Internal". - */ - -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[] = { - "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", - }; - int attr; - - def_conf = snd_hda_codec_get_pincfg(codec, pin); - - switch (get_defcfg_device(def_conf)) { - case AC_JACK_MIC_IN: - if (!check_location) - return "Mic"; - attr = snd_hda_get_input_pin_attr(def_conf); - if (!attr) - return "None"; - return mic_names[attr - 1]; - case AC_JACK_LINE_IN: - if (!check_location) - return "Line"; - attr = snd_hda_get_input_pin_attr(def_conf); - if (!attr) - return "None"; - if (attr == INPUT_PIN_ATTR_DOCK) - return "Dock Line"; - return "Line"; - case AC_JACK_AUX: - return "Aux"; - case AC_JACK_CD: - return "CD"; - case AC_JACK_SPDIF_IN: - return "SPDIF In"; - case AC_JACK_DIG_OTHER_IN: - return "Digital In"; - default: - return "Misc"; - } -} - -/* 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 - * have to put "Front" prefix to each label. In such a case, returns false. - */ -static int check_mic_location_need(struct hda_codec *codec, - const struct auto_pin_cfg *cfg, - int input) -{ - unsigned int defc; - int i, attr, attr2; - - defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); - attr = snd_hda_get_input_pin_attr(defc); - /* for internal or docking mics, we need locations */ - if (attr <= INPUT_PIN_ATTR_NORMAL) - return 1; - - attr = 0; - for (i = 0; i < cfg->num_inputs; i++) { - defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); - attr2 = snd_hda_get_input_pin_attr(defc); - if (attr2 >= INPUT_PIN_ATTR_NORMAL) { - if (attr && attr != attr2) - return 1; /* different locations found */ - attr = attr2; - } - } - return 0; -} - -/** - * hda_get_autocfg_input_label - Get a label for the given input - * - * Get a label for the given input pin defined by the autocfg item. - * Unlike hda_get_input_pin_label(), this function checks all inputs - * defined in autocfg and avoids the redundant mic/line prefix as much as - * possible. - */ -const char *hda_get_autocfg_input_label(struct hda_codec *codec, - const struct auto_pin_cfg *cfg, - int input) -{ - int type = cfg->inputs[input].type; - int has_multiple_pins = 0; - - if ((input > 0 && cfg->inputs[input - 1].type == type) || - (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) - has_multiple_pins = 1; - if (has_multiple_pins && type == AUTO_PIN_MIC) - has_multiple_pins &= check_mic_location_need(codec, cfg, input); - return hda_get_input_pin_label(codec, cfg->inputs[input].pin, - has_multiple_pins); -} -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) -{ - static const char * const channel_sfx[] = { - " Front", " Surround", " CLFE", " Side" - }; - int 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 channel_sfx[i]; -} - -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->speaker_pins, cfg->speaker_outs, - indexp); - 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; -} - -/** - * 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. - */ -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); - const char *name = NULL; - int i; - - if (indexp) - *indexp = 0; - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - return 0; - - switch (get_defcfg_device(def_conf)) { - case AC_JACK_LINE_OUT: - return fill_audio_out_name(codec, nid, cfg, "Line Out", - label, maxlen, indexp); - case AC_JACK_SPEAKER: - return fill_audio_out_name(codec, nid, cfg, "Speaker", - label, maxlen, indexp); - case AC_JACK_HP_OUT: - 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) - name = "HDMI"; - else - name = "SPDIF"; - if (cfg && indexp) { - i = find_idx_in_nid_list(nid, cfg->dig_out_pins, - cfg->dig_outs); - if (i >= 0) - *indexp = i; - } - 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; - } - if (!name) - return 0; - strlcpy(label, name, maxlen); - return 1; -} -EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); - /** * snd_hda_add_imux_item - Add an item to input_mux * diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index d68948499fbc..2dd1c113a4c1 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -17,6 +17,7 @@ #include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #include "hda_jack.h" bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index c66655cf413a..8ae52465ec5d 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -12,6 +12,8 @@ #ifndef __SOUND_HDA_JACK_H #define __SOUND_HDA_JACK_H +struct auto_pin_cfg; + struct hda_jack_tbl { hda_nid_t nid; unsigned char action; /* event action (0 = none) */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index a5cee952547d..9a096a8e0fc5 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -262,6 +262,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); +int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, + int index, int *type_index_ret); /* * Channel mode helper @@ -393,72 +395,7 @@ struct hda_bus_unsolicited { struct hda_bus *bus; }; -/* - * Helper for automatic pin configuration - */ - -enum { - AUTO_PIN_MIC, - AUTO_PIN_LINE_IN, - AUTO_PIN_CD, - AUTO_PIN_AUX, - AUTO_PIN_LAST -}; - -enum { - AUTO_PIN_LINE_OUT, - AUTO_PIN_SPEAKER_OUT, - AUTO_PIN_HP_OUT -}; - -#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS -#define AUTO_CFG_MAX_INS 8 - -struct auto_pin_cfg_item { - hda_nid_t pin; - int type; -}; - -struct auto_pin_cfg; -const char *hda_get_autocfg_input_label(struct hda_codec *codec, - const struct auto_pin_cfg *cfg, - int input); -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); - -enum { - INPUT_PIN_ATTR_UNUSED, /* pin not connected */ - INPUT_PIN_ATTR_INT, /* internal mic/line-in */ - INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ - INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ - INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ - INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ -}; - -int snd_hda_get_input_pin_attr(unsigned int def_conf); - -struct auto_pin_cfg { - int line_outs; - /* sorted in the order of Front/Surr/CLFE/Side */ - hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS]; - int speaker_outs; - hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS]; - int hp_outs; - int line_out_type; /* AUTO_PIN_XXX_OUT */ - hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; - int num_inputs; - struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS]; - int dig_outs; - hda_nid_t dig_out_pins[2]; - hda_nid_t dig_in_pin; - hda_nid_t mono_out_pin; - int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */ - int dig_in_type; /* HDA_PCM_TYPE_XXX */ -}; - +/* helper macros to retrieve pin default-config values */ #define get_defcfg_connect(cfg) \ ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) #define get_defcfg_association(cfg) \ @@ -472,19 +409,6 @@ struct auto_pin_cfg { #define get_defcfg_misc(cfg) \ ((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) -/* bit-flags for snd_hda_parse_pin_def_config() behavior */ -#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ -#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ - -int snd_hda_parse_pin_defcfg(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids, - unsigned int cond_flags); - -/* older function */ -#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ - snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) - /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 723bb9cb5f09..d8b2d6dee986 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -28,6 +28,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index a3b70a8f6df8..19ae14f739cb 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -26,6 +26,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" /* */ diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index d290a8ff0108..d0d3540e39e7 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -30,6 +30,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #define WIDGET_CHIP_CTRL 0x15 #define WIDGET_DSP_CTRL 0x16 diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 48c6d8186e90..9647ed4d7929 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_auto_parser.h" #include "hda_jack.h" #include <sound/tlv.h> diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index b6767b4ced44..c8fdaaefe702 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -29,6 +29,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #define NUM_PINS 11 diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 884f8ad351fd..baf1edde244d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,6 +36,7 @@ #include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 92e11672b91c..db272fb5e579 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_auto_parser.h" #include "hda_jack.h" /* Pin Widget NID */ |