/*
 * HDA injector, part of the Chameleon Boot Loader Project
 *
 * Ported and adapted by Fabio (ErmaC), October 2016.
 *
 * HDA injector is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * HDA injector is distributed in the hope that it will be useful, but
 * WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "Platform.h"
#include "hda.h"

#ifndef DEBUG_HDA
#ifndef DEBUG_ALL
#define DEBUG_HDA 1
#else
#define DEBUG_HDA DEBUG_ALL
#endif
#endif

#if DEBUG_HDA == 0
#define DBG(...)
#else
#define DBG(...) DebugLog(DEBUG_HDA, __VA_ARGS__)
#endif

// HDA layout-id device injection by dmazar

#define HDA_VMIN  0x02 // Minor, Major Version
#define HDA_GCTL  0x08 // Global Control Register
#define HDA_ICO    0x60 // Immediate Command Output Interface
#define HDA_IRI    0x64 // Immediate Response Input Interface
#define HDA_ICS    0x68 // Immediate Command Status

/* Structures */

static hda_controller_devices know_hda_controller[] = {
  //8086  Intel Corporation
  { HDA_INTEL_OAK,  "Oaktrail"    /*, 0, 0 */ },
  { HDA_INTEL_BAY,  "BayTrail"    /*, 0, 0 */ },
  { HDA_INTEL_HSW1,  "Haswell"    /*, 0, 0 */ },
  { HDA_INTEL_HSW2,  "Haswell"    /*, 0, 0 */ },
  { HDA_INTEL_HSW3,  "Haswell"    /*, 0, 0 */ },
  { HDA_INTEL_BDW,  "Broadwell"    /*, 0, 0 */ },
  { HDA_INTEL_BROXTON_T,  "Broxton-T"  /*, 0, 0 */ },
  { HDA_INTEL_CPT,  "Cougar Point"    /*, 0, 0 */ },
  { HDA_INTEL_PATSBURG,  "Patsburg"    /*, 0, 0 */ },
  { HDA_INTEL_PPT1,  "Panther Point"    /*, 0, 0 */ },
  { HDA_INTEL_BRASWELL,  "Braswell"    /*, 0, 0 */ },
  { HDA_INTEL_82801F,  "82801F"    /*, 0, 0 */ },
  { HDA_INTEL_63XXESB,  "631x/632xESB"    /*, 0, 0 */ },
  { HDA_INTEL_82801G,  "82801G"    /*, 0, 0 */ },
  { HDA_INTEL_82801H,  "82801H"    /*, 0, 0 */ },
  { HDA_INTEL_82801I,  "82801I"    /*, 0, 0 */ },
  { HDA_INTEL_ICH9,  "ICH9"      /*, 0, 0 */ },
  { HDA_INTEL_82801JI,  "82801JI"    /*, 0, 0 */ },
  { HDA_INTEL_82801JD,  "82801JD"    /*, 0, 0 */ },
  { HDA_INTEL_PCH,  "5 Series/3400 Series"  /*, 0, 0 */ },
  { HDA_INTEL_PCH2,  "5 Series/3400 Series"  /*, 0, 0 */ },
  { HDA_INTEL_BROXTON_P,  "Apollolake"  /*, 0, 0 */ }, // Broxton-P
  { HDA_INTEL_SCH,  "SCH"      /*, 0, 0 */ },
  { HDA_INTEL_LPT1,  "Lynx Point"    /*, 0, 0 */ },
  { HDA_INTEL_LPT2,  "Lynx Point"    /*, 0, 0 */ },
  { HDA_INTEL_WCPT,  "Wildcat Point"    /*, 0, 0 */ },
  { HDA_INTEL_WELLS1,  "Wellsburg"    /*, 0, 0 */ },
  { HDA_INTEL_WELLS2,  "Wellsburg"    /*, 0, 0 */ },
  { HDA_INTEL_WCPTLP,  "Wildcat Point-LP"  /*, 0, 0 */ },
  { HDA_INTEL_LPTLP1,  "Lynx Point-LP"    /*, 0, 0 */ },
  { HDA_INTEL_LPTLP2,  "Lynx Point-LP"    /*, 0, 0 */ },
  { HDA_INTEL_SRSPLP,  "Sunrise Point-LP"  /*, 0, 0 */ },
  { HDA_INTEL_KABYLAKE_LP,  "Kabylake-LP"  /*, 0, 0 */ }, // Kabylake-LP
  { HDA_INTEL_SRSP,  "Sunrise Point"    /*, 0, 0 */ },
  { HDA_INTEL_KABYLAKE,  "Kabylake"  /*, 0, 0 */ }, // Kabylake
  { HDA_INTEL_LEWISBURG1,  "Lewisburg"  /*, 0, 0 */ }, // Lewisburg
  { HDA_INTEL_LEWISBURG2,  "Lewisburg"  /*, 0, 0 */ }, // Lewisburg
  { HDA_INTEL_UNPT,  "Union Point"    /*, 0, 0 */ }, // Kabylake-H

  //10de  NVIDIA Corporation
#if 0
  { HDA_NVIDIA_MCP51,  "MCP51" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_MCP55,  "MCP55" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_MCP61_1,  "MCP61" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP61_2,  "MCP61" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP65_1,  "MCP65" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP65_2,  "MCP65" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP67_1,  "MCP67" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP67_2,  "MCP67" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP73_1,  "MCP73" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP73_2,  "MCP73" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP78_1,  "MCP78" /*, 0, HDAC_QUIRK_64BIT */ },
  { HDA_NVIDIA_MCP78_2,  "MCP78" /*, 0, HDAC_QUIRK_64BIT */ },
  { HDA_NVIDIA_MCP78_3,  "MCP78" /*, 0, HDAC_QUIRK_64BIT */ },
  { HDA_NVIDIA_MCP78_4,  "MCP78" /*, 0, HDAC_QUIRK_64BIT */ },
#endif
  { HDA_NVIDIA_MCP79_1,  "MCP79" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP79_2,  "MCP79" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP79_3,  "MCP79" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP79_4,  "MCP79" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP89_1,  "MCP89" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP89_2,  "MCP89" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP89_3,  "MCP89" /*, 0, 0 */ },
  { HDA_NVIDIA_MCP89_4,  "MCP89" /*, 0, 0 */ },
  { HDA_NVIDIA_0BE2,  "(0x0be2)" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_0BE3,  "(0x0be3)" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_0BE4,  "(0x0be4)" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GT100,  "GT100" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GT104,  "GT104" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GT106,  "GT106" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GT108,  "GT108" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GT116,  "GT116" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GF119,  "GF119" /*, 0, 0 */ },
  { HDA_NVIDIA_GF110_1,  "GF110" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GF110_2,  "GF110" /*, 0, HDAC_QUIRK_MSI */ },
  { HDA_NVIDIA_GK110,  "GK110" /*, 0, ? */ },
  { HDA_NVIDIA_GK106,  "GK106" /*, 0, ? */ },
  { HDA_NVIDIA_GK107,  "GK107" /*, 0, ? */ },
  { HDA_NVIDIA_GK104,  "GK104" /*, 0, ? */ },
  { HDA_NVIDIA_GP104_2, "Pascal GP104-200" /*, 0, ? */ },
  { HDA_NVIDIA_GM204_2, "Maxwell GP204-200" /*, 0, ? */ },

  //1002  Advanced Micro Devices [AMD] nee ATI Technologies Inc
  { HDA_ATI_SB450,  "SB4x0" /*, 0, 0 */ },
  { HDA_ATI_SB600,  "SB600" /*, 0, 0 */ },
  { HDA_ATI_RS600,  "RS600" /*, 0, 0 */ },
  { HDA_ATI_HUDSON,  "Hudson" /*, 0, 0 */ },
  { HDA_ATI_RS690,  "RS690" /*, 0, 0 */ },
  { HDA_ATI_RS780,  "RS780" /*, 0, 0 */ },
  { HDA_ATI_RS880,  "RS880" /*, 0, 0 */ },
  { HDA_ATI_TRINITY,  "Trinity" /*, 0, ? */ },
  { HDA_ATI_R600,    "R600" /*, 0, 0 */ },
  { HDA_ATI_RV610,  "RV610" /*, 0, 0 */ },
  { HDA_ATI_RV620,  "RV620" /*, 0, 0 */ },
  { HDA_ATI_RV630,  "RV630" /*, 0, 0 */ },
  { HDA_ATI_RV635,  "RV635" /*, 0, 0 */ },
  { HDA_ATI_RV710,  "RV710" /*, 0, 0 */ },
  { HDA_ATI_RV730,  "RV730" /*, 0, 0 */ },
  { HDA_ATI_RV740,  "RV740" /*, 0, 0 */ },
  { HDA_ATI_RV770,  "RV770" /*, 0, 0 */ },
  { HDA_ATI_RV810,  "RV810" /*, 0, 0 */ },
  { HDA_ATI_RV830,  "RV830" /*, 0, 0 */ },
  { HDA_ATI_RV840,  "RV840" /*, 0, 0 */ },
  { HDA_ATI_RV870,  "RV870" /*, 0, 0 */ },
  { HDA_ATI_RV910,  "RV910" /*, 0, 0 */ },
  { HDA_ATI_RV930,  "RV930" /*, 0, 0 */ },
  { HDA_ATI_RV940,  "RV940" /*, 0, 0 */ },
  { HDA_ATI_RV970,  "RV970" /*, 0, 0 */ },
  { HDA_ATI_R1000,  "R1000" /*, 0, 0 */ }, // HDMi
  { HDA_ATI_SI,    "SI" /*, 0, 0 */ },
  { HDA_ATI_VERDE,  "Cape Verde" /*, 0, ? */ }, // HDMi

  //17f3  RDC Semiconductor, Inc.
  { HDA_RDC_M3010,  "M3010" /*, 0, 0 */ },

  //1106  VIA Technologies, Inc.
  { HDA_VIA_VT82XX,  "VT8251/8237A" /*, 0, 0 */ },

  //1039  Silicon Integrated Systems [SiS]
  { HDA_SIS_966,    "966" /*, 0, 0 */ },

  //10b9  ULi Electronics Inc.(Split off ALi Corporation in 2003)
  { HDA_ULI_M5461,  "M5461" /*, 0, 0 */ },

  /* Unknown */
  { HDA_INTEL_ALL,  "Unknown Intel device" /*, 0, 0 */ },
  { HDA_NVIDIA_ALL,  "Unknown NVIDIA device" /*, 0, 0 */ },
  { HDA_ATI_ALL,    "Unknown ATI device" /*, 0, 0 */ },
  { HDA_VIA_ALL,    "Unknown VIA device" /*, 0, 0 */ },
  { HDA_SIS_ALL,    "Unknown SiS device" /*, 0, 0 */ },
  { HDA_ULI_ALL,    "Unknown ULI device" /*, 0, 0 */ },
};
#define HDAC_DEVICES_LEN (sizeof(know_hda_controller) / sizeof(know_hda_controller[0]))

/* CODECs */
/*
 * ErmaC: There's definitely a lot of different versions of the same audio codec variant out there...
 * in the next struct you will find a "generic" but IMHO detailed list of
 * possible codec... anyway to specific a new one or find difference beetween revision
 * check it under linux enviroment with:
 * $cat /proc/asound/Intel/codec#0
 * --------------------------------
 *  Codec: Analog Devices AD1989B
 *  Address: 0
 *  AFG Function Id: 0x1 (unsol 0)
 *  Vendor Id: 0x11d4989b
 *  Subsystem Id: 0x10438372
 *  Revision Id: 0x100300
 * --------------------------------
 * or
 * $cat /proc/asound/NVidia/codec#0
 * --------------------------------
 *  Codec: Nvidia GPU 14 HDMI/DP
 *  Address: 0
 *  AFG Function Id: 0x1 (unsol 0)
 *  Vendor Id: 0x10de0014
 *  Subsystem Id: 0x10de0101
 *  Revision Id: 0x100100
 * --------------------------------
 */
#if 0
static hdacc_codecs know_codecs[] = {
  { HDA_CODEC_CS4206, 0,    "CS4206" },
  { HDA_CODEC_CS4207, 0,    "CS4207" },
  { HDA_CODEC_CS4208, 0,    "CS4208" },
  { HDA_CODEC_CS4210, 0,    "CS4210" },
  { HDA_CODEC_CS4213, 0,          "CS4213" },

  { HDA_CODEC_ALC221, 0,          "ALC221" },
  { HDA_CODEC_ALC231, 0,          "ALC231" },
  { HDA_CODEC_ALC233, 0,          "ALC233" },
  { HDA_CODEC_ALC233, 0x0003,  "ALC3236" },
  { HDA_CODEC_ALC235, 0,          "ALC235" },
  { HDA_CODEC_ALC255, 0,          "ALC255" },
  { HDA_CODEC_ALC256, 0,          "ALC256" },
  { HDA_CODEC_ALC260, 0,          "ALC260" },
  //  { HDA_CODEC_ALC262, 0x0100,  "ALC262" }, // Revision Id: 0x100100
  { HDA_CODEC_ALC262, 0,          "ALC262" },
  { HDA_CODEC_ALC267, 0,          "ALC267" },
  { HDA_CODEC_ALC268, 0,          "ALC268" },
  { HDA_CODEC_ALC269, 0,          "ALC269" },
  { HDA_CODEC_ALC270, 0,          "ALC270" },
  { HDA_CODEC_ALC272, 0,          "ALC272" },
  { HDA_CODEC_ALC273, 0,          "ALC273" },
  { HDA_CODEC_ALC275, 0,          "ALC275" },
  { HDA_CODEC_ALC276, 0,          "ALC276" },
  { HDA_CODEC_ALC280, 0,          "ALC280" },
  { HDA_CODEC_ALC282, 0,          "ALC282" },
  { HDA_CODEC_ALC283, 0,          "ALC283" },
  { HDA_CODEC_ALC284, 0,          "ALC284" },
  { HDA_CODEC_ALC285, 0,          "ALC285" },
  { HDA_CODEC_ALC286, 0,          "ALC286" },
  { HDA_CODEC_ALC288, 0,          "ALC288" },
  { HDA_CODEC_ALC290, 0,          "ALC290" },
  { HDA_CODEC_ALC292, 0,          "ALC292" },
  { HDA_CODEC_ALC292, 0x0001,     "ALC3232" },
  { HDA_CODEC_ALC293, 0,          "ALC293" },
  { HDA_CODEC_ALC298, 0,          "ALC298" },
  { HDA_CODEC_ALC660, 0,          "ALC660-VD" },
  { HDA_CODEC_ALC662, 0,          "ALC662" },
  { HDA_CODEC_ALC662, 0x0101,  "ALC662 rev1" },
  { HDA_CODEC_ALC662, 0x0002,  "ALC662 rev2" },
  { HDA_CODEC_ALC662, 0x0300,  "ALC662 rev3" },
  { HDA_CODEC_ALC663, 0,          "ALC663" },
  { HDA_CODEC_ALC665, 0,          "ALC665" },
  { HDA_CODEC_ALC667, 0,          "ALC667" },
  { HDA_CODEC_ALC668, 0,          "ALC668" },
  { HDA_CODEC_ALC670, 0,          "ALC670" },
  { HDA_CODEC_ALC671, 0,          "ALC671" },
  { HDA_CODEC_ALC680, 0,          "ALC680" },
  { HDA_CODEC_ALC861, 0x0340,  "ALC660" },
  { HDA_CODEC_ALC861, 0,          "ALC861" },
  { HDA_CODEC_ALC861VD, 0,        "ALC861-VD" },
  { HDA_CODEC_ALC867, 0,          "ALC891" },
  //  { HDA_CODEC_ALC880, 0x0800,  "ALC880" }, // Revision Id: 0x100800
  { HDA_CODEC_ALC880, 0,          "ALC880" },
  { HDA_CODEC_ALC882, 0,          "ALC882" },
  { HDA_CODEC_ALC883, 0,          "ALC883" },
  { HDA_CODEC_ALC885, 0x0101,  "ALC889A" }, // Revision Id: 0x100101
  { HDA_CODEC_ALC885, 0x0103,  "ALC889A" }, // Revision Id: 0x100103
  { HDA_CODEC_ALC885, 0,          "ALC885" },
  { HDA_CODEC_ALC886, 0,          "ALC886" },
  { HDA_CODEC_ALC887, 0,          "ALC887" },
  { HDA_CODEC_ALC888, 0x0101,  "ALC1200" }, // Revision Id: 0x100101
  { HDA_CODEC_ALC888, 0,          "ALC888" },
  { HDA_CODEC_ALC889, 0,          "ALC889" },
  { HDA_CODEC_ALC892, 0,          "ALC892" },
  { HDA_CODEC_ALC898, 0,          "ALC898" },
  //  { HDA_CODEC_ALC899, 0,    "ALC899" },
  { HDA_CODEC_ALC1150, 0,         "ALC1150" },
  { HDA_CODEC_ALC1220A, 0,        "ALCS1220A" },
  { HDA_CODEC_ALC1220, 0,         "ALC1220" },

  { HDA_CODEC_AD1882, 0,          "AD1882" },
  { HDA_CODEC_AD1882A, 0,         "AD1882A" },
  { HDA_CODEC_AD1883, 0,          "AD1883" },
  { HDA_CODEC_AD1884, 0,          "AD1884" },
  { HDA_CODEC_AD1884A, 0,         "AD1884A" },
  { HDA_CODEC_AD1981HD, 0,        "AD1981HD" },
  { HDA_CODEC_AD1983, 0,          "AD1983" },
  { HDA_CODEC_AD1984, 0,          "AD1984" },
  { HDA_CODEC_AD1984A, 0,         "AD1984A" },
  { HDA_CODEC_AD1984B, 0,         "AD1984B" },
  { HDA_CODEC_AD1986A, 0,         "AD1986A" },
  { HDA_CODEC_AD1987, 0,          "AD1987" },
  { HDA_CODEC_AD1988, 0,          "AD1988A" },
  { HDA_CODEC_AD1988B, 0,         "AD1988B" },
  { HDA_CODEC_AD1989A, 0,         "AD1989A" },
  { HDA_CODEC_AD1989B, 0x0200,    "AD2000B" }, // Revision Id: 0x100200
  { HDA_CODEC_AD1989B, 0x0300,    "AD2000B" }, // Revision Id: 0x100300
  { HDA_CODEC_AD1989B, 0,         "AD1989B" },

  { HDA_CODEC_XFIEA, 0,           "X-Fi Extreme A" },
  { HDA_CODEC_XFIED, 0,           "X-Fi Extreme D" },
  { HDA_CODEC_CA0132, 0,          "CA0132" },
  { HDA_CODEC_SB0880, 0,          "SB0880 X-Fi" },
  { HDA_CODEC_CMI9880, 0,         "CMI9880" },
  { HDA_CODEC_CMI98802, 0,        "CMI9880" },

  { HDA_CODEC_CXD9872RDK, 0,      "CXD9872RD/K" },
  { HDA_CODEC_CXD9872AKD, 0,      "CXD9872AKD" },
  { HDA_CODEC_STAC9200D, 0,       "STAC9200D" },
  { HDA_CODEC_STAC9204X, 0,       "STAC9204X" },
  { HDA_CODEC_STAC9204D, 0,       "STAC9204D" },
  { HDA_CODEC_STAC9205X, 0,       "STAC9205X" },
  { HDA_CODEC_STAC9205D, 0,       "STAC9205D" },
  { HDA_CODEC_STAC9220, 0,        "STAC9220" },
  { HDA_CODEC_STAC9220_A1, 0,     "STAC9220_A1" },
  { HDA_CODEC_STAC9220_A2, 0,     "STAC9220_A2" },
  { HDA_CODEC_STAC9221, 0,        "STAC9221" },
  { HDA_CODEC_STAC9221_A2, 0,     "STAC9221_A2" },
  { HDA_CODEC_STAC9221D, 0,       "STAC9221D" },
  { HDA_CODEC_STAC922XD, 0,       "STAC9220D/9223D" },
  { HDA_CODEC_STAC9227X, 0,       "STAC9227X" },
  { HDA_CODEC_STAC9227D, 0,       "STAC9227D" },
  { HDA_CODEC_STAC9228X, 0,       "STAC9228X" },
  { HDA_CODEC_STAC9228D, 0,       "STAC9228D" },
  { HDA_CODEC_STAC9229X, 0,       "STAC9229X" },
  { HDA_CODEC_STAC9229D, 0,       "STAC9229D" },
  { HDA_CODEC_STAC9230X, 0,       "STAC9230X" },
  { HDA_CODEC_STAC9230D, 0,       "STAC9230D" },
  { HDA_CODEC_STAC9250, 0,        "STAC9250" },
  { HDA_CODEC_STAC9250D, 0,  "STAC9250D" },
  { HDA_CODEC_STAC9251, 0,        "STAC9251" },
  { HDA_CODEC_STAC9250D_1, 0,  "STAC9250D" },
  { HDA_CODEC_STAC9255, 0,        "STAC9255" },
  { HDA_CODEC_STAC9255D, 0,       "STAC9255D" },
  { HDA_CODEC_STAC9254, 0,        "STAC9254" },
  { HDA_CODEC_STAC9254D, 0,       "STAC9254D" },
  { HDA_CODEC_STAC9271X, 0,       "STAC9271X" },
  { HDA_CODEC_STAC9271D, 0,       "STAC9271D" },
  { HDA_CODEC_STAC9272X, 0,       "STAC9272X" },
  { HDA_CODEC_STAC9272D, 0,       "STAC9272D" },
  { HDA_CODEC_STAC9273X, 0,       "STAC9273X" },
  { HDA_CODEC_STAC9273D, 0,       "STAC9273D" },
  { HDA_CODEC_STAC9274, 0,        "STAC9274" },
  { HDA_CODEC_STAC9274D, 0,       "STAC9274D" },
  { HDA_CODEC_STAC9274X5NH, 0,    "STAC9274X5NH" },
  { HDA_CODEC_STAC9274D5NH, 0,    "STAC9274D5NH" },
  { HDA_CODEC_STAC9202, 0,  "STAC9202" },
  { HDA_CODEC_STAC9202D, 0,  "STAC9202D" },
  { HDA_CODEC_STAC9872AK, 0,      "STAC9872AK" },

  { HDA_CODEC_IDT92HD005, 0,      "92HD005" },
  { HDA_CODEC_IDT92HD005D, 0,     "92HD005D" },
  { HDA_CODEC_IDT92HD206X, 0,     "92HD206X" },
  { HDA_CODEC_IDT92HD206D, 0,     "92HD206D" },
  { HDA_CODEC_IDT92HD66B1X5, 0,   "92HD66B1X5" },
  { HDA_CODEC_IDT92HD66B2X5, 0,   "92HD66B2X5" },
  { HDA_CODEC_IDT92HD66B3X5, 0,   "92HD66B3X5" },
  { HDA_CODEC_IDT92HD66C1X5, 0,   "92HD66C1X5" },
  { HDA_CODEC_IDT92HD66C2X5, 0,   "92HD66C2X5" },
  { HDA_CODEC_IDT92HD66C3X5, 0,   "92HD66C3X5" },
  { HDA_CODEC_IDT92HD66B1X3, 0,   "92HD66B1X3" },
  { HDA_CODEC_IDT92HD66B2X3, 0,   "92HD66B2X3" },
  { HDA_CODEC_IDT92HD66B3X3, 0,   "92HD66B3X3" },
  { HDA_CODEC_IDT92HD66C1X3, 0,   "92HD66C1X3" },
  { HDA_CODEC_IDT92HD66C2X3, 0,   "92HD66C2X3" },
  { HDA_CODEC_IDT92HD66C3_65, 0,  "92HD66C3_65" },
  { HDA_CODEC_IDT92HD700X, 0,     "92HD700X" },
  { HDA_CODEC_IDT92HD700D, 0,     "92HD700D" },
  { HDA_CODEC_IDT92HD71B5, 0,     "92HD71B5" },
  { HDA_CODEC_IDT92HD71B5_2, 0,   "92HD71B5" },
  { HDA_CODEC_IDT92HD71B6, 0,     "92HD71B6" },
  { HDA_CODEC_IDT92HD71B6_2, 0,   "92HD71B6" },
  { HDA_CODEC_IDT92HD71B7, 0,     "92HD71B7" },
  { HDA_CODEC_IDT92HD71B7_2, 0,   "92HD71B7" },
  { HDA_CODEC_IDT92HD71B8, 0,     "92HD71B8" },
  { HDA_CODEC_IDT92HD71B8_2, 0,   "92HD71B8" },
  { HDA_CODEC_IDT92HD73C1, 0,     "92HD73C1" },
  { HDA_CODEC_IDT92HD73D1, 0,     "92HD73D1" },
  { HDA_CODEC_IDT92HD73E1, 0,     "92HD73E1" },
  { HDA_CODEC_IDT92HD95, 0,  "92HD95" },
  { HDA_CODEC_IDT92HD75B3, 0,     "92HD75B3" },
  { HDA_CODEC_IDT92HD88B3, 0,     "92HD88B3" },
  { HDA_CODEC_IDT92HD88B1, 0,     "92HD88B1" },
  { HDA_CODEC_IDT92HD88B2, 0,     "92HD88B2" },
  { HDA_CODEC_IDT92HD88B4, 0,     "92HD88B4" },
  { HDA_CODEC_IDT92HD75BX, 0,     "92HD75BX" },
  { HDA_CODEC_IDT92HD81B1C, 0,    "92HD81B1C" },
  { HDA_CODEC_IDT92HD81B1X, 0,    "92HD81B1X" },
  { HDA_CODEC_IDT92HD83C1C, 0,    "92HD83C1C" },
  { HDA_CODEC_IDT92HD83C1X, 0,    "92HD83C1X" },
  { HDA_CODEC_IDT92HD87B1_3, 0,   "92HD87B1/3" },
  { HDA_CODEC_IDT92HD87B2_4, 0,   "92HD87B2/4" },
  { HDA_CODEC_IDT92HD89C3, 0,     "92HD89C3" },
  { HDA_CODEC_IDT92HD89C2, 0,     "92HD89C2" },
  { HDA_CODEC_IDT92HD89C1, 0,     "92HD89C1" },
  { HDA_CODEC_IDT92HD89B3, 0,     "92HD89B3" },
  { HDA_CODEC_IDT92HD89B2, 0,     "92HD89B2" },
  { HDA_CODEC_IDT92HD89B1, 0,     "92HD89B1" },
  { HDA_CODEC_IDT92HD89E3, 0,     "92HD89E3" },
  { HDA_CODEC_IDT92HD89E2, 0,     "92HD89E2" },
  { HDA_CODEC_IDT92HD89E1, 0,     "92HD89E1" },
  { HDA_CODEC_IDT92HD89D3, 0,     "92HD89D3" },
  { HDA_CODEC_IDT92HD89D2, 0,     "92HD89D2" },
  { HDA_CODEC_IDT92HD89D1, 0,     "92HD89D1" },
  { HDA_CODEC_IDT92HD89F3, 0,     "92HD89F3" },
  { HDA_CODEC_IDT92HD89F2, 0,     "92HD89F2" },
  { HDA_CODEC_IDT92HD89F1, 0,     "92HD89F1" },
  { HDA_CODEC_IDT92HD90BXX, 0,    "92HD90BXX" },
  { HDA_CODEC_IDT92HD91BXX, 0,    "92HD91BXX" },
  { HDA_CODEC_IDT92HD93BXX, 0,    "92HD93BXX" },
  { HDA_CODEC_IDT92HD98BXX, 0,    "92HD98BXX" },
  { HDA_CODEC_IDT92HD99BXX, 0,    "92HD99BXX" },

  { HDA_CODEC_CX20549, 0,         "CX20549 (Venice)" },
  { HDA_CODEC_CX20551, 0,         "CX20551 (Waikiki)" },
  { HDA_CODEC_CX20561, 0,         "CX20561 (Hermosa)" },
  { HDA_CODEC_CX20582, 0,         "CX20582 (Pebble)" },
  { HDA_CODEC_CX20583, 0,         "CX20583 (Pebble HSF)" },
  { HDA_CODEC_CX20584, 0,         "CX20584" },
  { HDA_CODEC_CX20585, 0,         "CX20585" },
  { HDA_CODEC_CX20588, 0,         "CX20588" },
  { HDA_CODEC_CX20590, 0,         "CX20590" },
  { HDA_CODEC_CX20631, 0,         "CX20631" },
  { HDA_CODEC_CX20632, 0,         "CX20632" },
  { HDA_CODEC_CX20641, 0,         "CX20641" },
  { HDA_CODEC_CX20642, 0,         "CX20642" },
  { HDA_CODEC_CX20651, 0,         "CX20651" },
  { HDA_CODEC_CX20652, 0,         "CX20652" },
  { HDA_CODEC_CX20664, 0,         "CX20664" },
  { HDA_CODEC_CX20665, 0,         "CX20665" },
  { HDA_CODEC_CX20751, 0,    "CX20751/2" },
  { HDA_CODEC_CX20751_2, 0,  "CX20751/2" },
  { HDA_CODEC_CX20751_4, 0,  "CX20753/4" },
  { HDA_CODEC_CX20755, 0,         "CX20755" },
  { HDA_CODEC_CX20756, 0,         "CX20756" },
  { HDA_CODEC_CX20757, 0,         "CX20757" },
  { HDA_CODEC_CX20952, 0,         "CX20952" },

  { HDA_CODEC_VT1708_8, 0,        "VT1708_8" },
  { HDA_CODEC_VT1708_9, 0,        "VT1708_9" },
  { HDA_CODEC_VT1708_A, 0,        "VT1708_A" },
  { HDA_CODEC_VT1708_B, 0,        "VT1708_B" },
  { HDA_CODEC_VT1709_0, 0,        "VT1709_0" },
  { HDA_CODEC_VT1709_1, 0,        "VT1709_1" },
  { HDA_CODEC_VT1709_2, 0,        "VT1709_2" },
  { HDA_CODEC_VT1709_3, 0,        "VT1709_3" },
  { HDA_CODEC_VT1709_4, 0,        "VT1709_4" },
  { HDA_CODEC_VT1709_5, 0,        "VT1709_5" },
  { HDA_CODEC_VT1709_6, 0,        "VT1709_6" },
  { HDA_CODEC_VT1709_7, 0,        "VT1709_7" },
  { HDA_CODEC_VT1708B_0, 0,       "VT1708B_0" },
  { HDA_CODEC_VT1708B_1, 0,       "VT1708B_1" },
  { HDA_CODEC_VT1708B_2, 0,       "VT1708B_2" },
  { HDA_CODEC_VT1708B_3, 0,       "VT1708B_3" },
  { HDA_CODEC_VT1708B_4, 0,       "VT1708B_4" },
  { HDA_CODEC_VT1708B_5, 0,       "VT1708B_5" },
  { HDA_CODEC_VT1708B_6, 0,       "VT1708B_6" },
  { HDA_CODEC_VT1708B_7, 0,       "VT1708B_7" },
  { HDA_CODEC_VT1708S_0, 0,       "VT1708S_0" },
  { HDA_CODEC_VT1708S_1, 0,       "VT1708S_1" },
  { HDA_CODEC_VT1708S_2, 0,       "VT1708S_2" },
  { HDA_CODEC_VT1708S_3, 0,       "VT1708S_3" },
  { HDA_CODEC_VT1708S_4, 0,       "VT1708S_4" },
  { HDA_CODEC_VT1708S_5, 0,       "VT1708S_5" },
  { HDA_CODEC_VT1708S_6, 0,       "VT1708S_6" },
  { HDA_CODEC_VT1708S_7, 0,       "VT1708S_7" },
  { HDA_CODEC_VT1702_0, 0,        "VT1702_0" },
  { HDA_CODEC_VT1702_1, 0,        "VT1702_1" },
  { HDA_CODEC_VT1702_2, 0,        "VT1702_2" },
  { HDA_CODEC_VT1702_3, 0,        "VT1702_3" },
  { HDA_CODEC_VT1702_4, 0,        "VT1702_4" },
  { HDA_CODEC_VT1702_5, 0,        "VT1702_5" },
  { HDA_CODEC_VT1702_6, 0,        "VT1702_6" },
  { HDA_CODEC_VT1702_7, 0,        "VT1702_7" },
  { HDA_CODEC_VT1716S_0, 0,       "VT1716S_0" },
  { HDA_CODEC_VT1716S_1, 0,       "VT1716S_1" },
  { HDA_CODEC_VT1718S_0, 0,       "VT1718S_0" },
  { HDA_CODEC_VT1718S_1, 0,       "VT1718S_1" },
  { HDA_CODEC_VT1802_0, 0,        "VT1802_0" },
  { HDA_CODEC_VT1802_1, 0,        "VT1802_1" },
  { HDA_CODEC_VT1812, 0,          "VT1812" },
  { HDA_CODEC_VT1818S, 0,         "VT1818S" },
  { HDA_CODEC_VT1828S, 0,         "VT1828S" },
  { HDA_CODEC_VT2002P_0, 0,       "VT2002P_0" },
  { HDA_CODEC_VT2002P_1, 0,       "VT2002P_1" },
  { HDA_CODEC_VT2020, 0,          "VT2020" },

  { HDA_CODEC_ATIRS600_1, 0,      "RS600" },
  { HDA_CODEC_ATIRS600_2, 0,      "RS600" },
  { HDA_CODEC_ATIRS690, 0,        "RS690/780" },
  { HDA_CODEC_ATIR6XX, 0,         "R6xx" },

  { HDA_CODEC_NVIDIAMCP67, 0,     "MCP67" },
  { HDA_CODEC_NVIDIAMCP73, 0,     "MCP73" },
  { HDA_CODEC_NVIDIAMCP78, 0,     "MCP78" },
  { HDA_CODEC_NVIDIAMCP78_2, 0,   "MCP78" },
  { HDA_CODEC_NVIDIAMCP78_3, 0,   "MCP78" },
  { HDA_CODEC_NVIDIAMCP78_4, 0,   "MCP78" },
  { HDA_CODEC_NVIDIAMCP7A, 0,     "MCP7A" },
  { HDA_CODEC_NVIDIAGT220, 0,     "GT220" },
  { HDA_CODEC_NVIDIAGT21X, 0,     "GT21x" },
  { HDA_CODEC_NVIDIAMCP89, 0,     "MCP89" },
  { HDA_CODEC_NVIDIAGT240, 0,     "GT240" },
  { HDA_CODEC_NVIDIAGTS450, 0,    "GTS450" },
  { HDA_CODEC_NVIDIAGT440, 0,     "GT440" }, // Revision Id: 0x100100
  { HDA_CODEC_NVIDIAGTX470, 0,     "GT470" },
  { HDA_CODEC_NVIDIAGTX550, 0,    "GTX550" },
  { HDA_CODEC_NVIDIAGTX570, 0,    "GTX570" },
  { HDA_CODEC_NVIDIAGT610, 0,  "GT610" },

  { HDA_CODEC_INTELIBEXPEAK2, 0,      "Ibex Peak" },
  { HDA_CODEC_INTELBEARLAKE, 0,       "Bearlake" },
  { HDA_CODEC_INTELCANTIGA, 0,        "Cantiga" },
  { HDA_CODEC_INTELEAGLELAKE, 0,      "Eaglelake" },
  { HDA_CODEC_INTELIBEXPEAK, 0,       "Ibex Peak" },
  { HDA_CODEC_INTELCOUGARPOINT, 0,    "Cougar Point" },
  { HDA_CODEC_INTELPANTHERPOINT, 0,   "Panther Point" },
  { HDA_CODEC_INTELHASWELL, 0,        "Haswell" },
  { HDA_CODEC_INTELBROADWELL, 0,      "Broadwell" },
  { HDA_CODEC_INTELSKYLAKE, 0,        "Skylake" },
  { HDA_CODEC_INTELBROXTON, 0,        "Broxton" },
  { HDA_CODEC_INTELKABYLAKE, 0,       "Kabylake" },
  { HDA_CODEC_INTELCDT, 0,            "CedarTrail" },
  { HDA_CODEC_INTELVLV, 0,            "Valleyview2" },
  { HDA_CODEC_INTELBSW, 0,            "Braswell" },
  { HDA_CODEC_INTELCRESTLINE, 0,      "Crestline" },

  { HDA_CODEC_SII1390, 0,         "SiI1390 HDMi" },
  { HDA_CODEC_SII1392, 0,         "SiI1392 HDMi" },

  // Unknown CODECs
  { HDA_CODEC_ADXXXX, 0,          "Analog Devices" },
  { HDA_CODEC_AGEREXXXX, 0,       "LSI" },
  { HDA_CODEC_ALCXXXX, 0,         "Realtek" },
  { HDA_CODEC_ATIXXXX, 0,         "ATI" },
  { HDA_CODEC_CAXXXX, 0,          "Creative" },
  { HDA_CODEC_CMIXXXX, 0,         "CMedia" },
  { HDA_CODEC_CMIXXXX2, 0,        "CMedia" },
  { HDA_CODEC_CSXXXX, 0,          "Cirrus Logic" },
  { HDA_CODEC_CXXXXX, 0,          "Conexant" },
  { HDA_CODEC_CHXXXX, 0,          "Chrontel" },
  { HDA_CODEC_LGXXXX, 0,          "LG" },
  { HDA_CODEC_WMXXXX, 0,          "Wolfson Microelectronics" },
  { HDA_CODEC_QEMUXXXX, 0,        "QEMU" },
  { HDA_CODEC_IDTXXXX, 0,         "IDT" },
  { HDA_CODEC_INTELXXXX, 0,       "Intel" },
  { HDA_CODEC_MOTOXXXX, 0,        "Motorola" },
  { HDA_CODEC_NVIDIAXXXX, 0,      "NVIDIA" },
  { HDA_CODEC_SIIXXXX, 0,         "Silicon Image" },
  { HDA_CODEC_STACXXXX, 0,        "Sigmatel" },
  { HDA_CODEC_VTXXXX, 0,          "VIA" },
};
#define HDACC_CODECS_LEN (sizeof(know_codecs) / sizeof(know_codecs[0]))
#endif

/*****************
 * Device Methods
 *****************/

/* get HDA device name */
CHAR8 *get_hda_controller_name(UINT16 controller_device_id, UINT16 controller_vendor_id)
{
  static char desc[128];

  CHAR8 *name_format  = "Unknown HD Audio device %a";
  UINT32 controller_model = ((controller_device_id << 16) | controller_vendor_id);
  INT32 i;

  /* Get format for vendor ID */
  switch (controller_vendor_id)
  {
    case VEN_ATI_ID:
      name_format = "ATI %a HDA Controller (HDMi)"; break;

    case VEN_INTEL_ID:
      name_format = "Intel %a HDA Controller"; break;

    case VEN_NVIDIA_ID:
      name_format = "Nvidia %a HDA Controller (HDMi)"; break;

    case VEN_RDC_ID:
      name_format = "RDC %a HDA Controller"; break;

    case VEN_SIS_ID:
      name_format = "SiS %a HDA Controller"; break;

    case VEN_ULI_ID:
      name_format = "ULI %a HDA Controller"; break;

    case VEN_VIA_ID:
      name_format = "VIA %a HDA Controller"; break;

    default:
      break;
  }

  for (i = 0; i < HDAC_DEVICES_LEN; i++)
  {
    if (know_hda_controller[i].model == controller_model)
    {
      AsciiSPrint(desc, sizeof(desc), name_format, know_hda_controller[i].desc);
      return desc;
    }
  }

  /* Not in table */
  AsciiSPrint(desc, sizeof(desc), "Unknown HDA device, vendor %04x, model %04x",
              controller_vendor_id, controller_device_id);
  return desc;
}
#if 0
/* get Codec name */
CHAR8 *get_hda_codec_name(UINT16 codec_vendor_id, UINT16 codec_device_id, UINT8 codec_revision_id, UINT8 codec_stepping_id)
{
  static char desc[128];

  CHAR8    *lName_format  = NULL;
  UINT32    lCodec_model = ((UINT32)(codec_vendor_id) << 16) + (codec_device_id);
  UINT32    lCodec_rev = (((UINT16)(codec_revision_id) << 8) + codec_stepping_id);
  INT32    i;

  // Get format for vendor ID
  switch ( codec_vendor_id ) // UINT16
  {
    case VEN_ATI_ID:
      lName_format = "ATI %a"; break;

    case  VEN_CIRRUSLOGIC_ID:
      lName_format = "Cirrus Logic %a"; break;

    case  VEN_MOTO_ID:
      lName_format = "Motorola %a"; break;

    case  VEN_SII_ID:
      lName_format = "Silicon Image %a"; break;

    case  VEN_NVIDIA_ID:
      lName_format = "Nvidia %a"; break;

    case  VEN_REALTEK_ID:
      lName_format = "Realtek %a"; break;

    case  VEN_CREATIVE_ID:
      lName_format = "Creative %a"; break;

    case  VEN_VIA_ID:
      lName_format = "VIA %a"; break;

    case  VEN_IDT_ID:
      lName_format = "IDT %a"; break;

    case  VEN_AGERE_ID:
      lName_format = "LSI %a"; break;

    case  VEN_ANALOGDEVICES_ID:
      lName_format = "Analog Devices %a"; break;

    case  VEN_CMEDIA_ID:
    case  VEN_CMEDIA2_ID:
      lName_format = "CMedia %a"; break;

    case  VEN_CONEXANT_ID:
      lName_format = "Conexant %s"; break;

    case  VEN_CHRONTEL_ID:
      lName_format = "Chrontel %a"; break;

    case  VEN_LG_ID:
      lName_format = "LG %a"; break;

    case  VEN_WOLFSON_ID:
      lName_format = "Wolfson Microelectronics %a"; break;

    case  VEN_QEMU_ID:
      lName_format = "QEMU %a"; break;

    case  VEN_INTEL_ID:
      lName_format = "Intel %a"; break;

    case  VEN_SIGMATEL_ID:
      lName_format = "Sigmatel %a"; break;

    default:
      lName_format = UNKNOWN; break;
      break;
  }

  for (i = 0; i < HDACC_CODECS_LEN; i++)
  {
    if ( know_codecs[i].id == lCodec_model )
    {
      if ( ( know_codecs[i].rev == 0x00000000 ) || ( know_codecs[i].rev == lCodec_rev ) )
      {
        AsciiSPrint(desc, sizeof(desc), lName_format, know_codecs[i].name);
        return desc;
      }
    }
  }

  if ( AsciiStrStr(lName_format, "%a" ) != NULL )
  {
    // Dirty way to remove '%a' from the end of the lName_format
    lName_format[AsciiStrLen(lName_format)-3] = '\0';
  }

  // Not in table
  AsciiSPrint(desc, sizeof(desc), "unknown %a Codec", lName_format);
  return desc;
}

#endif

#if 0
// executing HDA verb command using Immediate Command Input and Output Registers
UINT32 HDA_IC_sendVerb(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 codecAdr, UINT32 nodeId, UINT32 verb)
{
  EFI_STATUS  Status;
  UINT16    ics = 0;
  UINT32    data32 = 0;
  UINT64    data64 = 0;

  // about that polling below ...
  // spec says that delay is in 100ns units. value 1.000.000.0
  // should then be 1 second, but users of newer Aptio boards were reporting
  // delays of 10-20 secs when this value was used. maybe this polling timeout
  // value does not mean the same on all implementations?
  // anyway, delay is lowered now to 10.000.0 (10 millis).

  // poll ICS[0] to become 0
  Status = PciIo->PollMem(PciIo, EfiPciIoWidthUint16, 0/*bar*/, HDA_ICS/*offset*/, 0x1/*mask*/, 0/*value*/, 100000/*delay in 100ns*/, &data64);
  ics = (UINT16)(data64 & 0xFFFF);
  //DBG("poll ICS[0] == 0: Status=%r, ICS=%x, ICS[0]=%d\n", Status, ics, (ics & 0x0001));
  if (EFI_ERROR(Status)) return 0;
  // prepare and write verb to ICO
  data32 = codecAdr << 28 | ((nodeId & 0xFF)<<20) | (verb & 0xFFFFF);
  Status = PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, 0, HDA_ICO, 1, &data32);
  //DBG("ICO write verb Codec=%x, Node=%x, verb=%x, command verb=%x: Status=%r\n", codecAdr, nodeId, verb, data32, Status);
  if (EFI_ERROR(Status)) return 0;
  // write 11b to ICS[1:0] to send command
  ics |= 0x3;
  Status = PciIo->Mem.Write(PciIo, EfiPciIoWidthUint16, 0, HDA_ICS, 1, &ics);
  //DBG("ICS[1:0] = 11b: Status=%r\n", Status);
  if (EFI_ERROR(Status)) return 0;
  // poll ICS[1:0] to become 10b
  Status = PciIo->PollMem(PciIo, EfiPciIoWidthUint16, 0/*bar*/, HDA_ICS/*offset*/, 0x3/*mask*/, 0x2/*value*/, 100000/*delay in 100ns*/, &data64);
  //DBG("poll ICS[0] == 0: Status=%r\n", Status);
  if (EFI_ERROR(Status)) return 0;
  // read IRI for VendorId/DeviceId
  Status = PciIo->Mem.Read(PciIo, EfiPciIoWidthUint32, 0, HDA_IRI, 1, &data32);
  if (EFI_ERROR(Status)) return 0;
  return data32;
}
#endif


BOOLEAN IsHDMIAudio(EFI_HANDLE PciDevHandle)
{
  EFI_STATUS          Status;
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINTN               Segment;
  UINTN               Bus;
  UINTN               Device;
  UINTN               Function;
  UINTN               Index;

  // get device PciIo protocol
  Status = gBS->OpenProtocol(PciDevHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  if (EFI_ERROR(Status)) {
    return FALSE;
  }

  // get device location
  Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
  if (EFI_ERROR(Status)) {
    return FALSE;
  }

  // iterate over all GFX devices and check for sibling
  for (Index = 0; Index < NGFX; Index++) {
    if (gGraphics[Index].Segment == Segment
        && gGraphics[Index].Bus == Bus
        && gGraphics[Index].Device == Device) {
      return TRUE;
    }
  }

  return FALSE;
}

BOOLEAN setup_hda_devprop(EFI_PCI_IO_PROTOCOL *PciIo, pci_dt_t *hda_dev, CHAR8 *OSVersion)
{
  DevPropDevice           *device = NULL;
  UINT32                  layoutId = 0;
  UINT32                  codecId = 0;
  BOOLEAN                 Injected = FALSE;
  UINTN                   i;

  if (!device_inject_string) {
    device_inject_string = devprop_create_string();
  }
  if (IsHDMIAudio(hda_dev->DeviceHandle)) {
    if (!gSettings.HDMIInjection) {
      return FALSE;
    }

    if (hda_dev && !hda_dev->used) {
      device = devprop_add_device_pci(device_inject_string, hda_dev, NULL);
      hda_dev->used = TRUE;
    }
    if (!device) {
      return FALSE;
    }

    if (gSettings.NrAddProperties != 0xFFFE) {
      for (i = 0; i < gSettings.NrAddProperties; i++) {
        if (gSettings.AddProperties[i].Device != DEV_HDMI) {
          continue;
        }
        Injected = TRUE;

        if (!gSettings.AddProperties[i].MenuItem.BValue) {
          //DBG("  disabled property Key: %a, len: %d\n", gSettings.AddProperties[i].Key, gSettings.AddProperties[i].ValueLen);
        } else {
          devprop_add_value(device,
                            gSettings.AddProperties[i].Key,
                            (UINT8*)gSettings.AddProperties[i].Value,
                            gSettings.AddProperties[i].ValueLen);
          //DBG("  added property Key: %a, len: %d\n", gSettings.AddProperties[i].Key, gSettings.AddProperties[i].ValueLen);
        }
      }
    }
    if (Injected) {
      DBG("Additional HDMI properties injected, continue\n");
      //return TRUE;
    } else {
      if (gSettings.UseIntelHDMI) {
        DBG(" HDMI Audio, used with HDA setting hda-gfx=onboard-2\n");
        devprop_add_value(device, "hda-gfx", (UINT8*)"onboard-2", 10);
      } else {
        DBG(" HDMI Audio, used without HDA setting hda-gfx=onboard-1\n");
        devprop_add_value(device, "hda-gfx", (UINT8*)"onboard-1", 10);
      }
    }
  } else {
    if (!gSettings.HDAInjection) {
      return FALSE;
    }
    if (hda_dev && !hda_dev->used) {
      device = devprop_add_device_pci(device_inject_string, hda_dev, NULL);
      hda_dev->used = TRUE;
    }
    if (!device) {
      return FALSE;
    }
    // HDA - determine layout-id
    if (gSettings.HDALayoutId > 0) {
      // layoutId is specified - use it
      layoutId = (UINT32)gSettings.HDALayoutId;
      DBG(" setting specified layout-id=%d (0x%x)\n", layoutId, layoutId);
    } else {
      layoutId = 12;
    }
    if (gSettings.NrAddProperties != 0xFFFE) {
      for (i = 0; i < gSettings.NrAddProperties; i++) {
        if (gSettings.AddProperties[i].Device != DEV_HDA) {
          continue;
        }
        Injected = TRUE;

        if (!gSettings.AddProperties[i].MenuItem.BValue) {
          //DBG("  disabled property Key: %a, len: %d\n", gSettings.AddProperties[i].Key, gSettings.AddProperties[i].ValueLen);
        } else {
          devprop_add_value(device,
                            gSettings.AddProperties[i].Key,
                            (UINT8*)gSettings.AddProperties[i].Value,
                            gSettings.AddProperties[i].ValueLen);
          //DBG("  added property Key: %a, len: %d\n", gSettings.AddProperties[i].Key, gSettings.AddProperties[i].ValueLen);
        }
      }
    }
    if (!Injected) {
      if ((OSVersion != NULL && AsciiOSVersionToUint64(OSVersion) < AsciiOSVersionToUint64("10.8")) || (gSettings.HDALayoutId > 0)) {
        devprop_add_value(device, "layout-id", (UINT8 *)&layoutId, 4);
      }
      layoutId = 0; // reuse variable
      if (gSettings.UseIntelHDMI) {
        devprop_add_value(device, "hda-gfx", (UINT8 *)"onboard-1", 10);
      }
      codecId = 1; // reuse variable again
      if (gSettings.AFGLowPowerState) {
        devprop_add_value(device, "AFGLowPowerState", (UINT8 *)&codecId, 4);
      }

      devprop_add_value(device, "MaximumBootBeepVolume", (UINT8 *)&layoutId, 1);
      devprop_add_value(device, "PinConfigurations", (UINT8 *)&layoutId, 1);
    }
  }
  return TRUE;
}

