162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * BIOS auto-parser helper functions for HD-audio 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <linux/sort.h> 1162306a36Sopenharmony_ci#include <sound/core.h> 1262306a36Sopenharmony_ci#include <sound/hda_codec.h> 1362306a36Sopenharmony_ci#include "hda_local.h" 1462306a36Sopenharmony_ci#include "hda_auto_parser.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * Helper for automatic pin configuration 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci for (; *list; list++) 2362306a36Sopenharmony_ci if (*list == nid) 2462306a36Sopenharmony_ci return 1; 2562306a36Sopenharmony_ci return 0; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* a pair of input pin and its sequence */ 2962306a36Sopenharmony_cistruct auto_out_pin { 3062306a36Sopenharmony_ci hda_nid_t pin; 3162306a36Sopenharmony_ci short seq; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int compare_seq(const void *ap, const void *bp) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci const struct auto_out_pin *a = ap; 3762306a36Sopenharmony_ci const struct auto_out_pin *b = bp; 3862306a36Sopenharmony_ci return (int)(a->seq - b->seq); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Sort an associated group of pins according to their sequence numbers. 4362306a36Sopenharmony_ci * then store it to a pin array. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistatic void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, 4662306a36Sopenharmony_ci int num_pins) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci int i; 4962306a36Sopenharmony_ci sort(list, num_pins, sizeof(list[0]), compare_seq, NULL); 5062306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) 5162306a36Sopenharmony_ci pins[i] = list[i].pin; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* add the found input-pin to the cfg->inputs[] table */ 5662306a36Sopenharmony_cistatic void add_auto_cfg_input_pin(struct hda_codec *codec, struct auto_pin_cfg *cfg, 5762306a36Sopenharmony_ci hda_nid_t nid, int type) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci if (cfg->num_inputs < AUTO_CFG_MAX_INS) { 6062306a36Sopenharmony_ci cfg->inputs[cfg->num_inputs].pin = nid; 6162306a36Sopenharmony_ci cfg->inputs[cfg->num_inputs].type = type; 6262306a36Sopenharmony_ci cfg->inputs[cfg->num_inputs].has_boost_on_pin = 6362306a36Sopenharmony_ci nid_has_volume(codec, nid, HDA_INPUT); 6462306a36Sopenharmony_ci cfg->num_inputs++; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int compare_input_type(const void *ap, const void *bp) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci const struct auto_pin_cfg_item *a = ap; 7162306a36Sopenharmony_ci const struct auto_pin_cfg_item *b = bp; 7262306a36Sopenharmony_ci if (a->type != b->type) 7362306a36Sopenharmony_ci return (int)(a->type - b->type); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* If has both hs_mic and hp_mic, pick the hs_mic ahead of hp_mic. */ 7662306a36Sopenharmony_ci if (a->is_headset_mic && b->is_headphone_mic) 7762306a36Sopenharmony_ci return -1; /* don't swap */ 7862306a36Sopenharmony_ci else if (a->is_headphone_mic && b->is_headset_mic) 7962306a36Sopenharmony_ci return 1; /* swap */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* In case one has boost and the other one has not, 8262306a36Sopenharmony_ci pick the one with boost first. */ 8362306a36Sopenharmony_ci return (int)(b->has_boost_on_pin - a->has_boost_on_pin); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Reorder the surround channels 8762306a36Sopenharmony_ci * ALSA sequence is front/surr/clfe/side 8862306a36Sopenharmony_ci * HDA sequence is: 8962306a36Sopenharmony_ci * 4-ch: front/surr => OK as it is 9062306a36Sopenharmony_ci * 6-ch: front/clfe/surr 9162306a36Sopenharmony_ci * 8-ch: front/clfe/rear/side|fc 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic void reorder_outputs(unsigned int nums, hda_nid_t *pins) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci switch (nums) { 9662306a36Sopenharmony_ci case 3: 9762306a36Sopenharmony_ci case 4: 9862306a36Sopenharmony_ci swap(pins[1], pins[2]); 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* check whether the given pin has a proper pin I/O capability bit */ 10462306a36Sopenharmony_cistatic bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin, 10562306a36Sopenharmony_ci unsigned int dev) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci unsigned int pincap = snd_hda_query_pin_caps(codec, pin); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* some old hardware don't return the proper pincaps */ 11062306a36Sopenharmony_ci if (!pincap) 11162306a36Sopenharmony_ci return true; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci switch (dev) { 11462306a36Sopenharmony_ci case AC_JACK_LINE_OUT: 11562306a36Sopenharmony_ci case AC_JACK_SPEAKER: 11662306a36Sopenharmony_ci case AC_JACK_HP_OUT: 11762306a36Sopenharmony_ci case AC_JACK_SPDIF_OUT: 11862306a36Sopenharmony_ci case AC_JACK_DIG_OTHER_OUT: 11962306a36Sopenharmony_ci return !!(pincap & AC_PINCAP_OUT); 12062306a36Sopenharmony_ci default: 12162306a36Sopenharmony_ci return !!(pincap & AC_PINCAP_IN); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic bool can_be_headset_mic(struct hda_codec *codec, 12662306a36Sopenharmony_ci struct auto_pin_cfg_item *item, 12762306a36Sopenharmony_ci int seq_number) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci int attr; 13062306a36Sopenharmony_ci unsigned int def_conf; 13162306a36Sopenharmony_ci if (item->type != AUTO_PIN_MIC) 13262306a36Sopenharmony_ci return false; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (item->is_headset_mic || item->is_headphone_mic) 13562306a36Sopenharmony_ci return false; /* Already assigned */ 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci def_conf = snd_hda_codec_get_pincfg(codec, item->pin); 13862306a36Sopenharmony_ci attr = snd_hda_get_input_pin_attr(def_conf); 13962306a36Sopenharmony_ci if (attr <= INPUT_PIN_ATTR_DOCK) 14062306a36Sopenharmony_ci return false; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (seq_number >= 0) { 14362306a36Sopenharmony_ci int seq = get_defcfg_sequence(def_conf); 14462306a36Sopenharmony_ci if (seq != seq_number) 14562306a36Sopenharmony_ci return false; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return true; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci * Parse all pin widgets and store the useful pin nids to cfg 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * The number of line-outs or any primary output is stored in line_outs, 15562306a36Sopenharmony_ci * and the corresponding output pins are assigned to line_out_pins[], 15662306a36Sopenharmony_ci * in the order of front, rear, CLFE, side, ... 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * If more extra outputs (speaker and headphone) are found, the pins are 15962306a36Sopenharmony_ci * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack 16062306a36Sopenharmony_ci * is detected, one of speaker of HP pins is assigned as the primary 16162306a36Sopenharmony_ci * output, i.e. to line_out_pins[0]. So, line_outs is always positive 16262306a36Sopenharmony_ci * if any analog output exists. 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * The analog input pins are assigned to inputs array. 16562306a36Sopenharmony_ci * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, 16662306a36Sopenharmony_ci * respectively. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ciint snd_hda_parse_pin_defcfg(struct hda_codec *codec, 16962306a36Sopenharmony_ci struct auto_pin_cfg *cfg, 17062306a36Sopenharmony_ci const hda_nid_t *ignore_nids, 17162306a36Sopenharmony_ci unsigned int cond_flags) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci hda_nid_t nid; 17462306a36Sopenharmony_ci short seq, assoc_line_out; 17562306a36Sopenharmony_ci struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; 17662306a36Sopenharmony_ci struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; 17762306a36Sopenharmony_ci struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; 17862306a36Sopenharmony_ci int i; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (!snd_hda_get_int_hint(codec, "parser_flags", &i)) 18162306a36Sopenharmony_ci cond_flags = i; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci memset(cfg, 0, sizeof(*cfg)); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci memset(line_out, 0, sizeof(line_out)); 18662306a36Sopenharmony_ci memset(speaker_out, 0, sizeof(speaker_out)); 18762306a36Sopenharmony_ci memset(hp_out, 0, sizeof(hp_out)); 18862306a36Sopenharmony_ci assoc_line_out = 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci for_each_hda_codec_node(nid, codec) { 19162306a36Sopenharmony_ci unsigned int wid_caps = get_wcaps(codec, nid); 19262306a36Sopenharmony_ci unsigned int wid_type = get_wcaps_type(wid_caps); 19362306a36Sopenharmony_ci unsigned int def_conf; 19462306a36Sopenharmony_ci short assoc, loc, conn, dev; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* read all default configuration for pin complex */ 19762306a36Sopenharmony_ci if (wid_type != AC_WID_PIN) 19862306a36Sopenharmony_ci continue; 19962306a36Sopenharmony_ci /* ignore the given nids (e.g. pc-beep returns error) */ 20062306a36Sopenharmony_ci if (ignore_nids && is_in_nid_list(nid, ignore_nids)) 20162306a36Sopenharmony_ci continue; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci def_conf = snd_hda_codec_get_pincfg(codec, nid); 20462306a36Sopenharmony_ci conn = get_defcfg_connect(def_conf); 20562306a36Sopenharmony_ci if (conn == AC_JACK_PORT_NONE) 20662306a36Sopenharmony_ci continue; 20762306a36Sopenharmony_ci loc = get_defcfg_location(def_conf); 20862306a36Sopenharmony_ci dev = get_defcfg_device(def_conf); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* workaround for buggy BIOS setups */ 21162306a36Sopenharmony_ci if (dev == AC_JACK_LINE_OUT) { 21262306a36Sopenharmony_ci if (conn == AC_JACK_PORT_FIXED || 21362306a36Sopenharmony_ci conn == AC_JACK_PORT_BOTH) 21462306a36Sopenharmony_ci dev = AC_JACK_SPEAKER; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (!check_pincap_validity(codec, nid, dev)) 21862306a36Sopenharmony_ci continue; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci switch (dev) { 22162306a36Sopenharmony_ci case AC_JACK_LINE_OUT: 22262306a36Sopenharmony_ci seq = get_defcfg_sequence(def_conf); 22362306a36Sopenharmony_ci assoc = get_defcfg_association(def_conf); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!(wid_caps & AC_WCAP_STEREO)) 22662306a36Sopenharmony_ci if (!cfg->mono_out_pin) 22762306a36Sopenharmony_ci cfg->mono_out_pin = nid; 22862306a36Sopenharmony_ci if (!assoc) 22962306a36Sopenharmony_ci continue; 23062306a36Sopenharmony_ci if (!assoc_line_out) 23162306a36Sopenharmony_ci assoc_line_out = assoc; 23262306a36Sopenharmony_ci else if (assoc_line_out != assoc) { 23362306a36Sopenharmony_ci codec_info(codec, 23462306a36Sopenharmony_ci "ignore pin 0x%x with mismatching assoc# 0x%x vs 0x%x\n", 23562306a36Sopenharmony_ci nid, assoc, assoc_line_out); 23662306a36Sopenharmony_ci continue; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) { 23962306a36Sopenharmony_ci codec_info(codec, 24062306a36Sopenharmony_ci "ignore pin 0x%x, too many assigned pins\n", 24162306a36Sopenharmony_ci nid); 24262306a36Sopenharmony_ci continue; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci line_out[cfg->line_outs].pin = nid; 24562306a36Sopenharmony_ci line_out[cfg->line_outs].seq = seq; 24662306a36Sopenharmony_ci cfg->line_outs++; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case AC_JACK_SPEAKER: 24962306a36Sopenharmony_ci seq = get_defcfg_sequence(def_conf); 25062306a36Sopenharmony_ci assoc = get_defcfg_association(def_conf); 25162306a36Sopenharmony_ci if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) { 25262306a36Sopenharmony_ci codec_info(codec, 25362306a36Sopenharmony_ci "ignore pin 0x%x, too many assigned pins\n", 25462306a36Sopenharmony_ci nid); 25562306a36Sopenharmony_ci continue; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci speaker_out[cfg->speaker_outs].pin = nid; 25862306a36Sopenharmony_ci speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; 25962306a36Sopenharmony_ci cfg->speaker_outs++; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci case AC_JACK_HP_OUT: 26262306a36Sopenharmony_ci seq = get_defcfg_sequence(def_conf); 26362306a36Sopenharmony_ci assoc = get_defcfg_association(def_conf); 26462306a36Sopenharmony_ci if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) { 26562306a36Sopenharmony_ci codec_info(codec, 26662306a36Sopenharmony_ci "ignore pin 0x%x, too many assigned pins\n", 26762306a36Sopenharmony_ci nid); 26862306a36Sopenharmony_ci continue; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci hp_out[cfg->hp_outs].pin = nid; 27162306a36Sopenharmony_ci hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; 27262306a36Sopenharmony_ci cfg->hp_outs++; 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci case AC_JACK_MIC_IN: 27562306a36Sopenharmony_ci add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_MIC); 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci case AC_JACK_LINE_IN: 27862306a36Sopenharmony_ci add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_LINE_IN); 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci case AC_JACK_CD: 28162306a36Sopenharmony_ci add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_CD); 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci case AC_JACK_AUX: 28462306a36Sopenharmony_ci add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_AUX); 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci case AC_JACK_SPDIF_OUT: 28762306a36Sopenharmony_ci case AC_JACK_DIG_OTHER_OUT: 28862306a36Sopenharmony_ci if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) { 28962306a36Sopenharmony_ci codec_info(codec, 29062306a36Sopenharmony_ci "ignore pin 0x%x, too many assigned pins\n", 29162306a36Sopenharmony_ci nid); 29262306a36Sopenharmony_ci continue; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci cfg->dig_out_pins[cfg->dig_outs] = nid; 29562306a36Sopenharmony_ci cfg->dig_out_type[cfg->dig_outs] = 29662306a36Sopenharmony_ci (loc == AC_JACK_LOC_HDMI) ? 29762306a36Sopenharmony_ci HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; 29862306a36Sopenharmony_ci cfg->dig_outs++; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci case AC_JACK_SPDIF_IN: 30162306a36Sopenharmony_ci case AC_JACK_DIG_OTHER_IN: 30262306a36Sopenharmony_ci cfg->dig_in_pin = nid; 30362306a36Sopenharmony_ci if (loc == AC_JACK_LOC_HDMI) 30462306a36Sopenharmony_ci cfg->dig_in_type = HDA_PCM_TYPE_HDMI; 30562306a36Sopenharmony_ci else 30662306a36Sopenharmony_ci cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Find a pin that could be a headset or headphone mic */ 31262306a36Sopenharmony_ci if (cond_flags & HDA_PINCFG_HEADSET_MIC || cond_flags & HDA_PINCFG_HEADPHONE_MIC) { 31362306a36Sopenharmony_ci bool hsmic = !!(cond_flags & HDA_PINCFG_HEADSET_MIC); 31462306a36Sopenharmony_ci bool hpmic = !!(cond_flags & HDA_PINCFG_HEADPHONE_MIC); 31562306a36Sopenharmony_ci for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) 31662306a36Sopenharmony_ci if (hsmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xc)) { 31762306a36Sopenharmony_ci cfg->inputs[i].is_headset_mic = 1; 31862306a36Sopenharmony_ci hsmic = false; 31962306a36Sopenharmony_ci } else if (hpmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xd)) { 32062306a36Sopenharmony_ci cfg->inputs[i].is_headphone_mic = 1; 32162306a36Sopenharmony_ci hpmic = false; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* If we didn't find our sequence number mark, fall back to any sequence number */ 32562306a36Sopenharmony_ci for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) { 32662306a36Sopenharmony_ci if (!can_be_headset_mic(codec, &cfg->inputs[i], -1)) 32762306a36Sopenharmony_ci continue; 32862306a36Sopenharmony_ci if (hsmic) { 32962306a36Sopenharmony_ci cfg->inputs[i].is_headset_mic = 1; 33062306a36Sopenharmony_ci hsmic = false; 33162306a36Sopenharmony_ci } else if (hpmic) { 33262306a36Sopenharmony_ci cfg->inputs[i].is_headphone_mic = 1; 33362306a36Sopenharmony_ci hpmic = false; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (hsmic) 33862306a36Sopenharmony_ci codec_dbg(codec, "Told to look for a headset mic, but didn't find any.\n"); 33962306a36Sopenharmony_ci if (hpmic) 34062306a36Sopenharmony_ci codec_dbg(codec, "Told to look for a headphone mic, but didn't find any.\n"); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* FIX-UP: 34462306a36Sopenharmony_ci * If no line-out is defined but multiple HPs are found, 34562306a36Sopenharmony_ci * some of them might be the real line-outs. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci if (!cfg->line_outs && cfg->hp_outs > 1 && 34862306a36Sopenharmony_ci !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { 34962306a36Sopenharmony_ci i = 0; 35062306a36Sopenharmony_ci while (i < cfg->hp_outs) { 35162306a36Sopenharmony_ci /* The real HPs should have the sequence 0x0f */ 35262306a36Sopenharmony_ci if ((hp_out[i].seq & 0x0f) == 0x0f) { 35362306a36Sopenharmony_ci i++; 35462306a36Sopenharmony_ci continue; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci /* Move it to the line-out table */ 35762306a36Sopenharmony_ci line_out[cfg->line_outs++] = hp_out[i]; 35862306a36Sopenharmony_ci cfg->hp_outs--; 35962306a36Sopenharmony_ci memmove(hp_out + i, hp_out + i + 1, 36062306a36Sopenharmony_ci sizeof(hp_out[0]) * (cfg->hp_outs - i)); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci memset(hp_out + cfg->hp_outs, 0, 36362306a36Sopenharmony_ci sizeof(hp_out[0]) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); 36462306a36Sopenharmony_ci if (!cfg->hp_outs) 36562306a36Sopenharmony_ci cfg->line_out_type = AUTO_PIN_HP_OUT; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* sort by sequence */ 37062306a36Sopenharmony_ci sort_pins_by_sequence(cfg->line_out_pins, line_out, cfg->line_outs); 37162306a36Sopenharmony_ci sort_pins_by_sequence(cfg->speaker_pins, speaker_out, 37262306a36Sopenharmony_ci cfg->speaker_outs); 37362306a36Sopenharmony_ci sort_pins_by_sequence(cfg->hp_pins, hp_out, cfg->hp_outs); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * FIX-UP: if no line-outs are detected, try to use speaker or HP pin 37762306a36Sopenharmony_ci * as a primary output 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci if (!cfg->line_outs && 38062306a36Sopenharmony_ci !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { 38162306a36Sopenharmony_ci if (cfg->speaker_outs) { 38262306a36Sopenharmony_ci cfg->line_outs = cfg->speaker_outs; 38362306a36Sopenharmony_ci memcpy(cfg->line_out_pins, cfg->speaker_pins, 38462306a36Sopenharmony_ci sizeof(cfg->speaker_pins)); 38562306a36Sopenharmony_ci cfg->speaker_outs = 0; 38662306a36Sopenharmony_ci memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 38762306a36Sopenharmony_ci cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 38862306a36Sopenharmony_ci } else if (cfg->hp_outs) { 38962306a36Sopenharmony_ci cfg->line_outs = cfg->hp_outs; 39062306a36Sopenharmony_ci memcpy(cfg->line_out_pins, cfg->hp_pins, 39162306a36Sopenharmony_ci sizeof(cfg->hp_pins)); 39262306a36Sopenharmony_ci cfg->hp_outs = 0; 39362306a36Sopenharmony_ci memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 39462306a36Sopenharmony_ci cfg->line_out_type = AUTO_PIN_HP_OUT; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci reorder_outputs(cfg->line_outs, cfg->line_out_pins); 39962306a36Sopenharmony_ci reorder_outputs(cfg->hp_outs, cfg->hp_pins); 40062306a36Sopenharmony_ci reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* sort inputs in the order of AUTO_PIN_* type */ 40362306a36Sopenharmony_ci sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), 40462306a36Sopenharmony_ci compare_input_type, NULL); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* 40762306a36Sopenharmony_ci * debug prints of the parsed results 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", 41062306a36Sopenharmony_ci codec->core.chip_name, cfg->line_outs, cfg->line_out_pins[0], 41162306a36Sopenharmony_ci cfg->line_out_pins[1], cfg->line_out_pins[2], 41262306a36Sopenharmony_ci cfg->line_out_pins[3], cfg->line_out_pins[4], 41362306a36Sopenharmony_ci cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : 41462306a36Sopenharmony_ci (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? 41562306a36Sopenharmony_ci "speaker" : "line")); 41662306a36Sopenharmony_ci codec_info(codec, " speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", 41762306a36Sopenharmony_ci cfg->speaker_outs, cfg->speaker_pins[0], 41862306a36Sopenharmony_ci cfg->speaker_pins[1], cfg->speaker_pins[2], 41962306a36Sopenharmony_ci cfg->speaker_pins[3], cfg->speaker_pins[4]); 42062306a36Sopenharmony_ci codec_info(codec, " hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", 42162306a36Sopenharmony_ci cfg->hp_outs, cfg->hp_pins[0], 42262306a36Sopenharmony_ci cfg->hp_pins[1], cfg->hp_pins[2], 42362306a36Sopenharmony_ci cfg->hp_pins[3], cfg->hp_pins[4]); 42462306a36Sopenharmony_ci codec_info(codec, " mono: mono_out=0x%x\n", cfg->mono_out_pin); 42562306a36Sopenharmony_ci if (cfg->dig_outs) 42662306a36Sopenharmony_ci codec_info(codec, " dig-out=0x%x/0x%x\n", 42762306a36Sopenharmony_ci cfg->dig_out_pins[0], cfg->dig_out_pins[1]); 42862306a36Sopenharmony_ci codec_info(codec, " inputs:\n"); 42962306a36Sopenharmony_ci for (i = 0; i < cfg->num_inputs; i++) { 43062306a36Sopenharmony_ci codec_info(codec, " %s=0x%x\n", 43162306a36Sopenharmony_ci hda_get_autocfg_input_label(codec, cfg, i), 43262306a36Sopenharmony_ci cfg->inputs[i].pin); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci if (cfg->dig_in_pin) 43562306a36Sopenharmony_ci codec_info(codec, " dig-in=0x%x\n", cfg->dig_in_pin); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_parse_pin_defcfg); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/** 44262306a36Sopenharmony_ci * snd_hda_get_input_pin_attr - Get the input pin attribute from pin config 44362306a36Sopenharmony_ci * @def_conf: pin configuration value 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * Guess the input pin attribute (INPUT_PIN_ATTR_XXX) from the given 44662306a36Sopenharmony_ci * default pin configuration value. 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ciint snd_hda_get_input_pin_attr(unsigned int def_conf) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci unsigned int loc = get_defcfg_location(def_conf); 45162306a36Sopenharmony_ci unsigned int conn = get_defcfg_connect(def_conf); 45262306a36Sopenharmony_ci if (conn == AC_JACK_PORT_NONE) 45362306a36Sopenharmony_ci return INPUT_PIN_ATTR_UNUSED; 45462306a36Sopenharmony_ci /* Windows may claim the internal mic to be BOTH, too */ 45562306a36Sopenharmony_ci if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) 45662306a36Sopenharmony_ci return INPUT_PIN_ATTR_INT; 45762306a36Sopenharmony_ci if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) 45862306a36Sopenharmony_ci return INPUT_PIN_ATTR_INT; 45962306a36Sopenharmony_ci if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) 46062306a36Sopenharmony_ci return INPUT_PIN_ATTR_DOCK; 46162306a36Sopenharmony_ci if (loc == AC_JACK_LOC_REAR) 46262306a36Sopenharmony_ci return INPUT_PIN_ATTR_REAR; 46362306a36Sopenharmony_ci if (loc == AC_JACK_LOC_FRONT) 46462306a36Sopenharmony_ci return INPUT_PIN_ATTR_FRONT; 46562306a36Sopenharmony_ci return INPUT_PIN_ATTR_NORMAL; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/** 47062306a36Sopenharmony_ci * hda_get_input_pin_label - Give a label for the given input pin 47162306a36Sopenharmony_ci * @codec: the HDA codec 47262306a36Sopenharmony_ci * @item: ping config item to refer 47362306a36Sopenharmony_ci * @pin: the pin NID 47462306a36Sopenharmony_ci * @check_location: flag to add the jack location prefix 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * When @check_location is true, the function checks the pin location 47762306a36Sopenharmony_ci * for mic and line-in pins, and set an appropriate prefix like "Front", 47862306a36Sopenharmony_ci * "Rear", "Internal". 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic const char *hda_get_input_pin_label(struct hda_codec *codec, 48162306a36Sopenharmony_ci const struct auto_pin_cfg_item *item, 48262306a36Sopenharmony_ci hda_nid_t pin, bool check_location) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci unsigned int def_conf; 48562306a36Sopenharmony_ci static const char * const mic_names[] = { 48662306a36Sopenharmony_ci "Internal Mic", "Dock Mic", "Mic", "Rear Mic", "Front Mic" 48762306a36Sopenharmony_ci }; 48862306a36Sopenharmony_ci int attr; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci def_conf = snd_hda_codec_get_pincfg(codec, pin); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci switch (get_defcfg_device(def_conf)) { 49362306a36Sopenharmony_ci case AC_JACK_MIC_IN: 49462306a36Sopenharmony_ci if (item && item->is_headset_mic) 49562306a36Sopenharmony_ci return "Headset Mic"; 49662306a36Sopenharmony_ci if (item && item->is_headphone_mic) 49762306a36Sopenharmony_ci return "Headphone Mic"; 49862306a36Sopenharmony_ci if (!check_location) 49962306a36Sopenharmony_ci return "Mic"; 50062306a36Sopenharmony_ci attr = snd_hda_get_input_pin_attr(def_conf); 50162306a36Sopenharmony_ci if (!attr) 50262306a36Sopenharmony_ci return "None"; 50362306a36Sopenharmony_ci return mic_names[attr - 1]; 50462306a36Sopenharmony_ci case AC_JACK_LINE_IN: 50562306a36Sopenharmony_ci if (!check_location) 50662306a36Sopenharmony_ci return "Line"; 50762306a36Sopenharmony_ci attr = snd_hda_get_input_pin_attr(def_conf); 50862306a36Sopenharmony_ci if (!attr) 50962306a36Sopenharmony_ci return "None"; 51062306a36Sopenharmony_ci if (attr == INPUT_PIN_ATTR_DOCK) 51162306a36Sopenharmony_ci return "Dock Line"; 51262306a36Sopenharmony_ci return "Line"; 51362306a36Sopenharmony_ci case AC_JACK_AUX: 51462306a36Sopenharmony_ci return "Aux"; 51562306a36Sopenharmony_ci case AC_JACK_CD: 51662306a36Sopenharmony_ci return "CD"; 51762306a36Sopenharmony_ci case AC_JACK_SPDIF_IN: 51862306a36Sopenharmony_ci return "SPDIF In"; 51962306a36Sopenharmony_ci case AC_JACK_DIG_OTHER_IN: 52062306a36Sopenharmony_ci return "Digital In"; 52162306a36Sopenharmony_ci case AC_JACK_HP_OUT: 52262306a36Sopenharmony_ci return "Headphone Mic"; 52362306a36Sopenharmony_ci default: 52462306a36Sopenharmony_ci return "Misc"; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* Check whether the location prefix needs to be added to the label. 52962306a36Sopenharmony_ci * If all mic-jacks are in the same location (e.g. rear panel), we don't 53062306a36Sopenharmony_ci * have to put "Front" prefix to each label. In such a case, returns false. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_cistatic int check_mic_location_need(struct hda_codec *codec, 53362306a36Sopenharmony_ci const struct auto_pin_cfg *cfg, 53462306a36Sopenharmony_ci int input) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci unsigned int defc; 53762306a36Sopenharmony_ci int i, attr, attr2; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); 54062306a36Sopenharmony_ci attr = snd_hda_get_input_pin_attr(defc); 54162306a36Sopenharmony_ci /* for internal or docking mics, we need locations */ 54262306a36Sopenharmony_ci if (attr <= INPUT_PIN_ATTR_NORMAL) 54362306a36Sopenharmony_ci return 1; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci attr = 0; 54662306a36Sopenharmony_ci for (i = 0; i < cfg->num_inputs; i++) { 54762306a36Sopenharmony_ci defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); 54862306a36Sopenharmony_ci attr2 = snd_hda_get_input_pin_attr(defc); 54962306a36Sopenharmony_ci if (attr2 >= INPUT_PIN_ATTR_NORMAL) { 55062306a36Sopenharmony_ci if (attr && attr != attr2) 55162306a36Sopenharmony_ci return 1; /* different locations found */ 55262306a36Sopenharmony_ci attr = attr2; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/** 55962306a36Sopenharmony_ci * hda_get_autocfg_input_label - Get a label for the given input 56062306a36Sopenharmony_ci * @codec: the HDA codec 56162306a36Sopenharmony_ci * @cfg: the parsed pin configuration 56262306a36Sopenharmony_ci * @input: the input index number 56362306a36Sopenharmony_ci * 56462306a36Sopenharmony_ci * Get a label for the given input pin defined by the autocfg item. 56562306a36Sopenharmony_ci * Unlike hda_get_input_pin_label(), this function checks all inputs 56662306a36Sopenharmony_ci * defined in autocfg and avoids the redundant mic/line prefix as much as 56762306a36Sopenharmony_ci * possible. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ciconst char *hda_get_autocfg_input_label(struct hda_codec *codec, 57062306a36Sopenharmony_ci const struct auto_pin_cfg *cfg, 57162306a36Sopenharmony_ci int input) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci int type = cfg->inputs[input].type; 57462306a36Sopenharmony_ci int has_multiple_pins = 0; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if ((input > 0 && cfg->inputs[input - 1].type == type) || 57762306a36Sopenharmony_ci (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) 57862306a36Sopenharmony_ci has_multiple_pins = 1; 57962306a36Sopenharmony_ci if (has_multiple_pins && type == AUTO_PIN_MIC) 58062306a36Sopenharmony_ci has_multiple_pins &= check_mic_location_need(codec, cfg, input); 58162306a36Sopenharmony_ci has_multiple_pins |= codec->force_pin_prefix; 58262306a36Sopenharmony_ci return hda_get_input_pin_label(codec, &cfg->inputs[input], 58362306a36Sopenharmony_ci cfg->inputs[input].pin, 58462306a36Sopenharmony_ci has_multiple_pins); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hda_get_autocfg_input_label); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* return the position of NID in the list, or -1 if not found */ 58962306a36Sopenharmony_cistatic int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci int i; 59262306a36Sopenharmony_ci for (i = 0; i < nums; i++) 59362306a36Sopenharmony_ci if (list[i] == nid) 59462306a36Sopenharmony_ci return i; 59562306a36Sopenharmony_ci return -1; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* get a unique suffix or an index number */ 59962306a36Sopenharmony_cistatic const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, 60062306a36Sopenharmony_ci int num_pins, int *indexp) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci static const char * const channel_sfx[] = { 60362306a36Sopenharmony_ci " Front", " Surround", " CLFE", " Side" 60462306a36Sopenharmony_ci }; 60562306a36Sopenharmony_ci int i; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci i = find_idx_in_nid_list(nid, pins, num_pins); 60862306a36Sopenharmony_ci if (i < 0) 60962306a36Sopenharmony_ci return NULL; 61062306a36Sopenharmony_ci if (num_pins == 1) 61162306a36Sopenharmony_ci return ""; 61262306a36Sopenharmony_ci if (num_pins > ARRAY_SIZE(channel_sfx)) { 61362306a36Sopenharmony_ci if (indexp) 61462306a36Sopenharmony_ci *indexp = i; 61562306a36Sopenharmony_ci return ""; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci return channel_sfx[i]; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic const char *check_output_pfx(struct hda_codec *codec, hda_nid_t nid) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 62362306a36Sopenharmony_ci int attr = snd_hda_get_input_pin_attr(def_conf); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* check the location */ 62662306a36Sopenharmony_ci switch (attr) { 62762306a36Sopenharmony_ci case INPUT_PIN_ATTR_DOCK: 62862306a36Sopenharmony_ci return "Dock "; 62962306a36Sopenharmony_ci case INPUT_PIN_ATTR_FRONT: 63062306a36Sopenharmony_ci return "Front "; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci return ""; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid, 63662306a36Sopenharmony_ci const hda_nid_t *pins, int num_pins) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci int i, j, idx = 0; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci const char *pfx = check_output_pfx(codec, nid); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci i = find_idx_in_nid_list(nid, pins, num_pins); 64362306a36Sopenharmony_ci if (i < 0) 64462306a36Sopenharmony_ci return -1; 64562306a36Sopenharmony_ci for (j = 0; j < i; j++) 64662306a36Sopenharmony_ci if (pfx == check_output_pfx(codec, pins[j])) 64762306a36Sopenharmony_ci idx++; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return idx; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, 65362306a36Sopenharmony_ci const struct auto_pin_cfg *cfg, 65462306a36Sopenharmony_ci const char *name, char *label, int maxlen, 65562306a36Sopenharmony_ci int *indexp) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 65862306a36Sopenharmony_ci int attr = snd_hda_get_input_pin_attr(def_conf); 65962306a36Sopenharmony_ci const char *pfx, *sfx = ""; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* handle as a speaker if it's a fixed line-out */ 66262306a36Sopenharmony_ci if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT) 66362306a36Sopenharmony_ci name = "Speaker"; 66462306a36Sopenharmony_ci pfx = check_output_pfx(codec, nid); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (cfg) { 66762306a36Sopenharmony_ci /* try to give a unique suffix if needed */ 66862306a36Sopenharmony_ci sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, 66962306a36Sopenharmony_ci indexp); 67062306a36Sopenharmony_ci if (!sfx) 67162306a36Sopenharmony_ci sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs, 67262306a36Sopenharmony_ci indexp); 67362306a36Sopenharmony_ci if (!sfx) { 67462306a36Sopenharmony_ci /* don't add channel suffix for Headphone controls */ 67562306a36Sopenharmony_ci int idx = get_hp_label_index(codec, nid, cfg->hp_pins, 67662306a36Sopenharmony_ci cfg->hp_outs); 67762306a36Sopenharmony_ci if (idx >= 0 && indexp) 67862306a36Sopenharmony_ci *indexp = idx; 67962306a36Sopenharmony_ci sfx = ""; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci snprintf(label, maxlen, "%s%s%s", pfx, name, sfx); 68362306a36Sopenharmony_ci return 1; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci#define is_hdmi_cfg(conf) \ 68762306a36Sopenharmony_ci (get_defcfg_location(conf) == AC_JACK_LOC_HDMI) 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/** 69062306a36Sopenharmony_ci * snd_hda_get_pin_label - Get a label for the given I/O pin 69162306a36Sopenharmony_ci * @codec: the HDA codec 69262306a36Sopenharmony_ci * @nid: pin NID 69362306a36Sopenharmony_ci * @cfg: the parsed pin configuration 69462306a36Sopenharmony_ci * @label: the string buffer to store 69562306a36Sopenharmony_ci * @maxlen: the max length of string buffer (including termination) 69662306a36Sopenharmony_ci * @indexp: the pointer to return the index number (for multiple ctls) 69762306a36Sopenharmony_ci * 69862306a36Sopenharmony_ci * Get a label for the given pin. This function works for both input and 69962306a36Sopenharmony_ci * output pins. When @cfg is given as non-NULL, the function tries to get 70062306a36Sopenharmony_ci * an optimized label using hda_get_autocfg_input_label(). 70162306a36Sopenharmony_ci * 70262306a36Sopenharmony_ci * This function tries to give a unique label string for the pin as much as 70362306a36Sopenharmony_ci * possible. For example, when the multiple line-outs are present, it adds 70462306a36Sopenharmony_ci * the channel suffix like "Front", "Surround", etc (only when @cfg is given). 70562306a36Sopenharmony_ci * If no unique name with a suffix is available and @indexp is non-NULL, the 70662306a36Sopenharmony_ci * index number is stored in the pointer. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ciint snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, 70962306a36Sopenharmony_ci const struct auto_pin_cfg *cfg, 71062306a36Sopenharmony_ci char *label, int maxlen, int *indexp) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 71362306a36Sopenharmony_ci const char *name = NULL; 71462306a36Sopenharmony_ci int i; 71562306a36Sopenharmony_ci bool hdmi; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (indexp) 71862306a36Sopenharmony_ci *indexp = 0; 71962306a36Sopenharmony_ci if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci switch (get_defcfg_device(def_conf)) { 72362306a36Sopenharmony_ci case AC_JACK_LINE_OUT: 72462306a36Sopenharmony_ci return fill_audio_out_name(codec, nid, cfg, "Line Out", 72562306a36Sopenharmony_ci label, maxlen, indexp); 72662306a36Sopenharmony_ci case AC_JACK_SPEAKER: 72762306a36Sopenharmony_ci return fill_audio_out_name(codec, nid, cfg, "Speaker", 72862306a36Sopenharmony_ci label, maxlen, indexp); 72962306a36Sopenharmony_ci case AC_JACK_HP_OUT: 73062306a36Sopenharmony_ci return fill_audio_out_name(codec, nid, cfg, "Headphone", 73162306a36Sopenharmony_ci label, maxlen, indexp); 73262306a36Sopenharmony_ci case AC_JACK_SPDIF_OUT: 73362306a36Sopenharmony_ci case AC_JACK_DIG_OTHER_OUT: 73462306a36Sopenharmony_ci hdmi = is_hdmi_cfg(def_conf); 73562306a36Sopenharmony_ci name = hdmi ? "HDMI" : "SPDIF"; 73662306a36Sopenharmony_ci if (cfg && indexp) 73762306a36Sopenharmony_ci for (i = 0; i < cfg->dig_outs; i++) { 73862306a36Sopenharmony_ci hda_nid_t pin = cfg->dig_out_pins[i]; 73962306a36Sopenharmony_ci unsigned int c; 74062306a36Sopenharmony_ci if (pin == nid) 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci c = snd_hda_codec_get_pincfg(codec, pin); 74362306a36Sopenharmony_ci if (hdmi == is_hdmi_cfg(c)) 74462306a36Sopenharmony_ci (*indexp)++; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci default: 74862306a36Sopenharmony_ci if (cfg) { 74962306a36Sopenharmony_ci for (i = 0; i < cfg->num_inputs; i++) { 75062306a36Sopenharmony_ci if (cfg->inputs[i].pin != nid) 75162306a36Sopenharmony_ci continue; 75262306a36Sopenharmony_ci name = hda_get_autocfg_input_label(codec, cfg, i); 75362306a36Sopenharmony_ci if (name) 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci if (!name) 75862306a36Sopenharmony_ci name = hda_get_input_pin_label(codec, NULL, nid, true); 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci if (!name) 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci strscpy(label, name, maxlen); 76462306a36Sopenharmony_ci return 1; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_pin_label); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/** 76962306a36Sopenharmony_ci * snd_hda_add_verbs - Add verbs to the init list 77062306a36Sopenharmony_ci * @codec: the HDA codec 77162306a36Sopenharmony_ci * @list: zero-terminated verb list to add 77262306a36Sopenharmony_ci * 77362306a36Sopenharmony_ci * Append the given verb list to the execution list. The verbs will be 77462306a36Sopenharmony_ci * performed at init and resume time via snd_hda_apply_verbs(). 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ciint snd_hda_add_verbs(struct hda_codec *codec, 77762306a36Sopenharmony_ci const struct hda_verb *list) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci const struct hda_verb **v; 78062306a36Sopenharmony_ci v = snd_array_new(&codec->verbs); 78162306a36Sopenharmony_ci if (!v) 78262306a36Sopenharmony_ci return -ENOMEM; 78362306a36Sopenharmony_ci *v = list; 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_add_verbs); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci/** 78962306a36Sopenharmony_ci * snd_hda_apply_verbs - Execute the init verb lists 79062306a36Sopenharmony_ci * @codec: the HDA codec 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_civoid snd_hda_apply_verbs(struct hda_codec *codec) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci const struct hda_verb **v; 79562306a36Sopenharmony_ci int i; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci snd_array_for_each(&codec->verbs, i, v) 79862306a36Sopenharmony_ci snd_hda_sequence_write(codec, *v); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_apply_verbs); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/** 80362306a36Sopenharmony_ci * snd_hda_apply_pincfgs - Set each pin config in the given list 80462306a36Sopenharmony_ci * @codec: the HDA codec 80562306a36Sopenharmony_ci * @cfg: NULL-terminated pin config table 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_civoid snd_hda_apply_pincfgs(struct hda_codec *codec, 80862306a36Sopenharmony_ci const struct hda_pintbl *cfg) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci for (; cfg->nid; cfg++) 81162306a36Sopenharmony_ci snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_apply_pincfgs); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic void set_pin_targets(struct hda_codec *codec, 81662306a36Sopenharmony_ci const struct hda_pintbl *cfg) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci for (; cfg->nid; cfg++) 81962306a36Sopenharmony_ci snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_civoid __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci const char *modelname = codec->fixup_name; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci while (id >= 0) { 82762306a36Sopenharmony_ci const struct hda_fixup *fix = codec->fixup_list + id; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (++depth > 10) 83062306a36Sopenharmony_ci break; 83162306a36Sopenharmony_ci if (fix->chained_before) 83262306a36Sopenharmony_ci __snd_hda_apply_fixup(codec, fix->chain_id, action, depth + 1); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci switch (fix->type) { 83562306a36Sopenharmony_ci case HDA_FIXUP_PINS: 83662306a36Sopenharmony_ci if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins) 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci codec_dbg(codec, "%s: Apply pincfg for %s\n", 83962306a36Sopenharmony_ci codec->core.chip_name, modelname); 84062306a36Sopenharmony_ci snd_hda_apply_pincfgs(codec, fix->v.pins); 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci case HDA_FIXUP_VERBS: 84362306a36Sopenharmony_ci if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs) 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci codec_dbg(codec, "%s: Apply fix-verbs for %s\n", 84662306a36Sopenharmony_ci codec->core.chip_name, modelname); 84762306a36Sopenharmony_ci snd_hda_add_verbs(codec, fix->v.verbs); 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case HDA_FIXUP_FUNC: 85062306a36Sopenharmony_ci if (!fix->v.func) 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci codec_dbg(codec, "%s: Apply fix-func for %s\n", 85362306a36Sopenharmony_ci codec->core.chip_name, modelname); 85462306a36Sopenharmony_ci fix->v.func(codec, fix, action); 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci case HDA_FIXUP_PINCTLS: 85762306a36Sopenharmony_ci if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins) 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci codec_dbg(codec, "%s: Apply pinctl for %s\n", 86062306a36Sopenharmony_ci codec->core.chip_name, modelname); 86162306a36Sopenharmony_ci set_pin_targets(codec, fix->v.pins); 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci default: 86462306a36Sopenharmony_ci codec_err(codec, "%s: Invalid fixup type %d\n", 86562306a36Sopenharmony_ci codec->core.chip_name, fix->type); 86662306a36Sopenharmony_ci break; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci if (!fix->chained || fix->chained_before) 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci id = fix->chain_id; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__snd_hda_apply_fixup); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/** 87662306a36Sopenharmony_ci * snd_hda_apply_fixup - Apply the fixup chain with the given action 87762306a36Sopenharmony_ci * @codec: the HDA codec 87862306a36Sopenharmony_ci * @action: fixup action (HDA_FIXUP_ACT_XXX) 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_civoid snd_hda_apply_fixup(struct hda_codec *codec, int action) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci if (codec->fixup_list) 88362306a36Sopenharmony_ci __snd_hda_apply_fixup(codec, codec->fixup_id, action, 0); 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_apply_fixup); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci#define IGNORE_SEQ_ASSOC (~(AC_DEFCFG_SEQUENCE | AC_DEFCFG_DEF_ASSOC)) 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic bool pin_config_match(struct hda_codec *codec, 89062306a36Sopenharmony_ci const struct hda_pintbl *pins, 89162306a36Sopenharmony_ci bool match_all_pins) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci const struct hda_pincfg *pin; 89462306a36Sopenharmony_ci int i; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci snd_array_for_each(&codec->init_pins, i, pin) { 89762306a36Sopenharmony_ci hda_nid_t nid = pin->nid; 89862306a36Sopenharmony_ci u32 cfg = pin->cfg; 89962306a36Sopenharmony_ci const struct hda_pintbl *t_pins; 90062306a36Sopenharmony_ci int found; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci t_pins = pins; 90362306a36Sopenharmony_ci found = 0; 90462306a36Sopenharmony_ci for (; t_pins->nid; t_pins++) { 90562306a36Sopenharmony_ci if (t_pins->nid == nid) { 90662306a36Sopenharmony_ci found = 1; 90762306a36Sopenharmony_ci if ((t_pins->val & IGNORE_SEQ_ASSOC) == (cfg & IGNORE_SEQ_ASSOC)) 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci else if ((cfg & 0xf0000000) == 0x40000000 && (t_pins->val & 0xf0000000) == 0x40000000) 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci else 91262306a36Sopenharmony_ci return false; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci if (match_all_pins && 91662306a36Sopenharmony_ci !found && (cfg & 0xf0000000) != 0x40000000) 91762306a36Sopenharmony_ci return false; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return true; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci/** 92462306a36Sopenharmony_ci * snd_hda_pick_pin_fixup - Pick up a fixup matching with the pin quirk list 92562306a36Sopenharmony_ci * @codec: the HDA codec 92662306a36Sopenharmony_ci * @pin_quirk: zero-terminated pin quirk list 92762306a36Sopenharmony_ci * @fixlist: the fixup list 92862306a36Sopenharmony_ci * @match_all_pins: all valid pins must match with the table entries 92962306a36Sopenharmony_ci */ 93062306a36Sopenharmony_civoid snd_hda_pick_pin_fixup(struct hda_codec *codec, 93162306a36Sopenharmony_ci const struct snd_hda_pin_quirk *pin_quirk, 93262306a36Sopenharmony_ci const struct hda_fixup *fixlist, 93362306a36Sopenharmony_ci bool match_all_pins) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci const struct snd_hda_pin_quirk *pq; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) 93862306a36Sopenharmony_ci return; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci for (pq = pin_quirk; pq->subvendor; pq++) { 94162306a36Sopenharmony_ci if ((codec->core.subsystem_id & 0xffff0000) != (pq->subvendor << 16)) 94262306a36Sopenharmony_ci continue; 94362306a36Sopenharmony_ci if (codec->core.vendor_id != pq->codec) 94462306a36Sopenharmony_ci continue; 94562306a36Sopenharmony_ci if (pin_config_match(codec, pq->pins, match_all_pins)) { 94662306a36Sopenharmony_ci codec->fixup_id = pq->value; 94762306a36Sopenharmony_ci#ifdef CONFIG_SND_DEBUG_VERBOSE 94862306a36Sopenharmony_ci codec->fixup_name = pq->name; 94962306a36Sopenharmony_ci codec_dbg(codec, "%s: picked fixup %s (pin match)\n", 95062306a36Sopenharmony_ci codec->core.chip_name, codec->fixup_name); 95162306a36Sopenharmony_ci#endif 95262306a36Sopenharmony_ci codec->fixup_list = fixlist; 95362306a36Sopenharmony_ci return; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/** 96062306a36Sopenharmony_ci * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string 96162306a36Sopenharmony_ci * @codec: the HDA codec 96262306a36Sopenharmony_ci * @models: NULL-terminated model string list 96362306a36Sopenharmony_ci * @quirk: zero-terminated PCI/codec SSID quirk list 96462306a36Sopenharmony_ci * @fixlist: the fixup list 96562306a36Sopenharmony_ci * 96662306a36Sopenharmony_ci * Pick up a fixup entry matching with the given model string or SSID. 96762306a36Sopenharmony_ci * If a fixup was already set beforehand, the function doesn't do anything. 96862306a36Sopenharmony_ci * When a special model string "nofixup" is given, also no fixup is applied. 96962306a36Sopenharmony_ci * 97062306a36Sopenharmony_ci * The function tries to find the matching model name at first, if given. 97162306a36Sopenharmony_ci * If the model string contains the SSID alias, try to look up with the given 97262306a36Sopenharmony_ci * alias ID. 97362306a36Sopenharmony_ci * If nothing matched, try to look up the PCI SSID. 97462306a36Sopenharmony_ci * If still nothing matched, try to look up the codec SSID. 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_civoid snd_hda_pick_fixup(struct hda_codec *codec, 97762306a36Sopenharmony_ci const struct hda_model_fixup *models, 97862306a36Sopenharmony_ci const struct snd_pci_quirk *quirk, 97962306a36Sopenharmony_ci const struct hda_fixup *fixlist) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci const struct snd_pci_quirk *q; 98262306a36Sopenharmony_ci int id = HDA_FIXUP_ID_NOT_SET; 98362306a36Sopenharmony_ci const char *name = NULL; 98462306a36Sopenharmony_ci const char *type = NULL; 98562306a36Sopenharmony_ci unsigned int vendor, device; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) 98862306a36Sopenharmony_ci return; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* when model=nofixup is given, don't pick up any fixups */ 99162306a36Sopenharmony_ci if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { 99262306a36Sopenharmony_ci id = HDA_FIXUP_ID_NO_FIXUP; 99362306a36Sopenharmony_ci fixlist = NULL; 99462306a36Sopenharmony_ci codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n", 99562306a36Sopenharmony_ci codec->core.chip_name); 99662306a36Sopenharmony_ci goto found; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* match with the model name string */ 100062306a36Sopenharmony_ci if (codec->modelname && models) { 100162306a36Sopenharmony_ci while (models->name) { 100262306a36Sopenharmony_ci if (!strcmp(codec->modelname, models->name)) { 100362306a36Sopenharmony_ci id = models->id; 100462306a36Sopenharmony_ci name = models->name; 100562306a36Sopenharmony_ci codec_dbg(codec, "%s: picked fixup %s (model specified)\n", 100662306a36Sopenharmony_ci codec->core.chip_name, codec->fixup_name); 100762306a36Sopenharmony_ci goto found; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci models++; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (!quirk) 101462306a36Sopenharmony_ci return; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* match with the SSID alias given by the model string "XXXX:YYYY" */ 101762306a36Sopenharmony_ci if (codec->modelname && 101862306a36Sopenharmony_ci sscanf(codec->modelname, "%04x:%04x", &vendor, &device) == 2) { 101962306a36Sopenharmony_ci q = snd_pci_quirk_lookup_id(vendor, device, quirk); 102062306a36Sopenharmony_ci if (q) { 102162306a36Sopenharmony_ci type = "alias SSID"; 102262306a36Sopenharmony_ci goto found_device; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* match with the PCI SSID */ 102762306a36Sopenharmony_ci q = snd_pci_quirk_lookup(codec->bus->pci, quirk); 102862306a36Sopenharmony_ci if (q) { 102962306a36Sopenharmony_ci type = "PCI SSID"; 103062306a36Sopenharmony_ci goto found_device; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* match with the codec SSID */ 103462306a36Sopenharmony_ci q = snd_pci_quirk_lookup_id(codec->core.subsystem_id >> 16, 103562306a36Sopenharmony_ci codec->core.subsystem_id & 0xffff, 103662306a36Sopenharmony_ci quirk); 103762306a36Sopenharmony_ci if (q) { 103862306a36Sopenharmony_ci type = "codec SSID"; 103962306a36Sopenharmony_ci goto found_device; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci return; /* no matching */ 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci found_device: 104562306a36Sopenharmony_ci id = q->value; 104662306a36Sopenharmony_ci#ifdef CONFIG_SND_DEBUG_VERBOSE 104762306a36Sopenharmony_ci name = q->name; 104862306a36Sopenharmony_ci#endif 104962306a36Sopenharmony_ci codec_dbg(codec, "%s: picked fixup %s for %s %04x:%04x\n", 105062306a36Sopenharmony_ci codec->core.chip_name, name ? name : "", 105162306a36Sopenharmony_ci type, q->subvendor, q->subdevice); 105262306a36Sopenharmony_ci found: 105362306a36Sopenharmony_ci codec->fixup_id = id; 105462306a36Sopenharmony_ci codec->fixup_list = fixlist; 105562306a36Sopenharmony_ci codec->fixup_name = name; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_pick_fixup); 1058