// SPDX-License-Identifier: GPL-2.0-or-later /* * BIOS auto-parser helper functions for HD-audio * * Copyright (c) 2012 Takashi Iwai <[email protected]> */ #include <linux/slab.h> #include <linux/export.h> #include <linux/sort.h> #include <sound/core.h> #include <sound/hda_codec.h> #include "hda_local.h" #include "hda_auto_parser.h" /* * Helper for automatic pin configuration */ static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) { … } /* a pair of input pin and its sequence */ struct auto_out_pin { … }; static int compare_seq(const void *ap, const void *bp) { … } /* * Sort an associated group of pins according to their sequence numbers. * then store it to a pin array. */ static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, int num_pins) { … } /* add the found input-pin to the cfg->inputs[] table */ static void add_auto_cfg_input_pin(struct hda_codec *codec, struct auto_pin_cfg *cfg, hda_nid_t nid, int type) { … } static int compare_input_type(const void *ap, const void *bp) { … } /* 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) { … } /* check whether the given pin has a proper pin I/O capability bit */ static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin, unsigned int dev) { … } static bool can_be_headset_mic(struct hda_codec *codec, struct auto_pin_cfg_item *item, int seq_number) { … } /* * 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) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hda_get_input_pin_attr - Get the input pin attribute from pin config * @def_conf: pin configuration value * * Guess the input pin attribute (INPUT_PIN_ATTR_XXX) from the given * default pin configuration value. */ int snd_hda_get_input_pin_attr(unsigned int def_conf) { … } EXPORT_SYMBOL_GPL(…); /** * hda_get_input_pin_label - Give a label for the given input pin * @codec: the HDA codec * @item: ping config item to refer * @pin: the pin NID * @check_location: flag to add the jack location prefix * * 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, const struct auto_pin_cfg_item *item, hda_nid_t pin, bool check_location) { … } /* 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) { … } /** * hda_get_autocfg_input_label - Get a label for the given input * @codec: the HDA codec * @cfg: the parsed pin configuration * @input: the input index number * * 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) { … } EXPORT_SYMBOL_GPL(…); /* 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) { … } /* 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 *check_output_pfx(struct hda_codec *codec, hda_nid_t nid) { … } static int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid, const hda_nid_t *pins, int num_pins) { … } 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) { … } #define is_hdmi_cfg(conf) … /** * snd_hda_get_pin_label - Get a label for the given I/O pin * @codec: the HDA codec * @nid: pin NID * @cfg: the parsed pin configuration * @label: the string buffer to store * @maxlen: the max length of string buffer (including termination) * @indexp: the pointer to return the index number (for multiple ctls) * * 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) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hda_add_verbs - Add verbs to the init list * @codec: the HDA codec * @list: zero-terminated verb list to add * * Append the given verb list to the execution list. The verbs will be * performed at init and resume time via snd_hda_apply_verbs(). */ int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hda_apply_verbs - Execute the init verb lists * @codec: the HDA codec */ void snd_hda_apply_verbs(struct hda_codec *codec) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hda_apply_pincfgs - Set each pin config in the given list * @codec: the HDA codec * @cfg: NULL-terminated pin config table */ void snd_hda_apply_pincfgs(struct hda_codec *codec, const struct hda_pintbl *cfg) { … } EXPORT_SYMBOL_GPL(…); static void set_pin_targets(struct hda_codec *codec, const struct hda_pintbl *cfg) { … } void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hda_apply_fixup - Apply the fixup chain with the given action * @codec: the HDA codec * @action: fixup action (HDA_FIXUP_ACT_XXX) */ void snd_hda_apply_fixup(struct hda_codec *codec, int action) { … } EXPORT_SYMBOL_GPL(…); #define IGNORE_SEQ_ASSOC … static bool pin_config_match(struct hda_codec *codec, const struct hda_pintbl *pins, bool match_all_pins) { … } /** * snd_hda_pick_pin_fixup - Pick up a fixup matching with the pin quirk list * @codec: the HDA codec * @pin_quirk: zero-terminated pin quirk list * @fixlist: the fixup list * @match_all_pins: all valid pins must match with the table entries */ void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, const struct hda_fixup *fixlist, bool match_all_pins) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string * @codec: the HDA codec * @models: NULL-terminated model string list * @quirk: zero-terminated PCI/codec SSID quirk list * @fixlist: the fixup list * * Pick up a fixup entry matching with the given model string or SSID. * If a fixup was already set beforehand, the function doesn't do anything. * When a special model string "nofixup" is given, also no fixup is applied. * * The function tries to find the matching model name at first, if given. * If the model string contains the SSID alias, try to look up with the given * alias ID. * If nothing matched, try to look up the PCI SSID. * If still nothing matched, try to look up the codec SSID. */ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, const struct snd_pci_quirk *quirk, const struct hda_fixup *fixlist) { … } EXPORT_SYMBOL_GPL(…);