/* * File: HdaCodecDump.c * * Copyright (c) 2018 John Davis * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", 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 OR COPYRIGHT HOLDERS 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 "HdaCodecDump.h" #include "StateGenerator.h" #include "AmlGenerator.h" CONST CHAR8 *gWidgetNames[HDA_WIDGET_TYPE_VENDOR + 1] = { "Audio Output", "Audio Input", "Audio Mixer", "Audio Selector", "Pin Complex", "Power Widget", "Volume Knob Widget", "Beep Generator Widget", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Vendor Defined Widget" }; CONST CHAR8 *gPortConnectivities[4] = { "Jack", "None", "Fixed", "Int Jack" }; CONST CHAR8 *gDefaultDevices[HDA_CONFIG_DEFAULT_DEVICE_OTHER + 1] = { "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Handset", "Line In", "Aux", "Mic", "Telephone", "SPDIF In", "Digital In", "Reserved", "Other" }; CONST CHAR8 *gSurfaces[4] = { "Ext", "Int", "Ext", "Other" }; CONST CHAR8 *gLocations[0xF + 1] = { "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", "Special", "Special", "Special", "Reserved", "Reserved", "Reserved", "Reserved" }; CONST CHAR8 *gConnTypes[HDA_CONFIG_DEFAULT_CONN_OTHER + 1] = { "Unknown", "1/8", "1/4", "ATAPI", "RCA", "Optical", "Digital", "Analog", "Multi", "XLR", "RJ11", "Combo", "Other", "Other", "Other", "Other" }; CONST CHAR8 *gColors[HDA_CONFIG_DEFAULT_COLOR_OTHER + 1] = { "Unknown", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow", "Purple", "Pink", "Reserved", "Reserved", "Reserved", "Reserved", "White", "Other" }; #define HDC_ID { 'H','D','C','O' } #define HdaLog(n, ...) MemLog(FALSE, 0, n, ##__VA_ARGS__) CONST CHAR8 hdcID[4] = HDC_ID; extern UINTN AudioNum; extern HDA_OUTPUTS AudioList[20]; extern EFI_AUDIO_IO_PROTOCOL *AudioIo; extern CHAR16 *OEMPath; VOID EFIAPI HdaCodecDumpPrintRatesFormats( IN UINT32 Rates, IN UINT32 Formats) { // Print sample rates. HdaLog(" rates [0x%04X]:", (UINT16)Rates); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8KHZ) HdaLog(" 8000"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_11KHZ) HdaLog(" 11025"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16KHZ) HdaLog(" 16000"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_22KHZ) HdaLog(" 22050"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32KHZ) HdaLog(" 32000"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_44KHZ) HdaLog(" 44100"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_48KHZ) HdaLog(" 48000"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_88KHZ) HdaLog(" 88200"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_96KHZ) HdaLog(" 96000"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_176KHZ) HdaLog(" 176400"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_192KHZ) HdaLog(" 192000"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_384KHZ) HdaLog(" 384000"); HdaLog("\n"); // Print bits. HdaLog(" bits [0x%04X]:", (UINT16)(Rates >> 16)); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8BIT) HdaLog(" 8"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16BIT) HdaLog(" 16"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_20BIT) HdaLog(" 20"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_24BIT) HdaLog(" 24"); if (Rates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32BIT) HdaLog(" 32"); HdaLog("\n"); // Print formats. HdaLog(" formats [0x%08X]:", Formats); if (Formats & HDA_PARAMETER_SUPPORTED_STREAM_FORMATS_PCM) HdaLog(" PCM"); if (Formats & HDA_PARAMETER_SUPPORTED_STREAM_FORMATS_FLOAT32) HdaLog(" FLOAT32"); if (Formats & HDA_PARAMETER_SUPPORTED_STREAM_FORMATS_AC3) HdaLog(" AC3"); HdaLog("\n"); } VOID EFIAPI HdaCodecDumpPrintAmpCaps( IN UINT32 AmpCaps) { if (AmpCaps) { HdaLog("ofs=0x%02X, nsteps=0x%02X, stepsize=%02X, mute=%u\n", HDA_PARAMETER_AMP_CAPS_OFFSET(AmpCaps), HDA_PARAMETER_AMP_CAPS_NUM_STEPS(AmpCaps), HDA_PARAMETER_AMP_CAPS_STEP_SIZE(AmpCaps), (AmpCaps & HDA_PARAMETER_AMP_CAPS_MUTE) != 0); } else HdaLog("N/A\n"); } VOID EFIAPI HdaCodecDumpPrintWidgets( IN EFI_HDA_IO_PROTOCOL *HdaIo, //IN HDA_WIDGET *Widgets, IN HDA_WIDGET_DEV *Widgets, IN UINTN WidgetCount) { // Print each widget. for (UINTN w = 0; w < WidgetCount; w++) { // Print header and capabilities. HdaLog("Node 0x%02X [%a] wcaps 0x%08X:", Widgets[w].NodeId, gWidgetNames[HDA_PARAMETER_WIDGET_CAPS_TYPE(Widgets[w].Capabilities)], Widgets[w].Capabilities); if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_STEREO) HdaLog(" Stereo"); else HdaLog(" Mono"); if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_DIGITAL) HdaLog(" Digital"); if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_IN_AMP) HdaLog(" Amp-In"); if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_OUT_AMP) HdaLog(" Amp-Out"); if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_L_R_SWAP) HdaLog(" R/L"); HdaLog("\n"); // Print input amp info. if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_IN_AMP) { // Print caps. HdaLog(" Amp-In caps: "); HdaCodecDumpPrintAmpCaps(Widgets[w].AmpInCapabilities); // Print default values. HdaLog(" Amp-In vals:"); for (UINT8 i = 0; i < HDA_PARAMETER_CONN_LIST_LENGTH_LEN(Widgets[w].ConnectionListLength); i++) { if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_STEREO) HdaLog(" [0x%02X 0x%02X]", Widgets[w].AmpInLeftDefaultGainMute[i], Widgets[w].AmpInRightDefaultGainMute[i]); else HdaLog(" [0x%02X]", Widgets[w].AmpInLeftDefaultGainMute[i]); } HdaLog("\n"); } // Print output amp info. if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_OUT_AMP) { // Print caps. HdaLog(" Amp-Out caps: "); HdaCodecDumpPrintAmpCaps(Widgets[w].AmpOutCapabilities); // Print default values. HdaLog(" Amp-Out vals:"); if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_STEREO) HdaLog(" [0x%02X 0x%02X]\n", Widgets[w].AmpOutLeftDefaultGainMute, Widgets[w].AmpOutRightDefaultGainMute); else HdaLog(" [0x%02X]\n", Widgets[w].AmpOutLeftDefaultGainMute); } // Print pin complexe info. if (HDA_PARAMETER_WIDGET_CAPS_TYPE(Widgets[w].Capabilities) == HDA_WIDGET_TYPE_PIN_COMPLEX) { // Print pin capabilities. HdaLog(" Pincap 0x%08X:", Widgets[w].PinCapabilities); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_INPUT) HdaLog(" IN"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_OUTPUT) HdaLog(" OUT"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_HEADPHONE) HdaLog(" HP"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_EAPD) HdaLog(" EAPD"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_TRIGGER) HdaLog(" Trigger"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_PRESENCE) HdaLog(" Detect"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_HBR) HdaLog(" HBR"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_HDMI) HdaLog(" HDMI"); if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_DISPLAYPORT) HdaLog(" DP"); HdaLog("\n"); // Print EAPD info. if (Widgets[w].PinCapabilities & HDA_PARAMETER_PIN_CAPS_EAPD) { HdaLog(" EAPD 0x%X:", Widgets[w].DefaultEapd); if (Widgets[w].DefaultEapd & HDA_EAPD_BTL_ENABLE_BTL) HdaLog(" BTL"); if (Widgets[w].DefaultEapd & HDA_EAPD_BTL_ENABLE_EAPD) HdaLog(" EAPD"); if (Widgets[w].DefaultEapd & HDA_EAPD_BTL_ENABLE_L_R_SWAP) HdaLog(" R/L"); HdaLog("\n"); } // Print pin default header. HdaLog(" Pin Default 0x%08X: [%a] %a at %a %a\n", Widgets[w].DefaultConfiguration, gPortConnectivities[HDA_VERB_GET_CONFIGURATION_DEFAULT_PORT_CONN(Widgets[w].DefaultConfiguration)], gDefaultDevices[HDA_VERB_GET_CONFIGURATION_DEFAULT_DEVICE(Widgets[w].DefaultConfiguration)], gSurfaces[HDA_VERB_GET_CONFIGURATION_DEFAULT_SURF(Widgets[w].DefaultConfiguration)], gLocations[HDA_VERB_GET_CONFIGURATION_DEFAULT_LOC(Widgets[w].DefaultConfiguration)]); // Print connection type and color. HdaLog(" Conn = %a, Color = %a\n", gConnTypes[HDA_VERB_GET_CONFIGURATION_DEFAULT_CONN_TYPE(Widgets[w].DefaultConfiguration)], gColors[HDA_VERB_GET_CONFIGURATION_DEFAULT_COLOR(Widgets[w].DefaultConfiguration)]); // Print default association and sequence. HdaLog(" DefAssociation = 0x%1X, Sequence = 0x%1X\n", HDA_VERB_GET_CONFIGURATION_DEFAULT_ASSOCIATION(Widgets[w].DefaultConfiguration), HDA_VERB_GET_CONFIGURATION_DEFAULT_SEQUENCE(Widgets[w].DefaultConfiguration)); // Print default pin control. HdaLog(" Pin-ctls: 0x%02X:", Widgets[w].DefaultPinControl); if (Widgets[w].DefaultPinControl & HDA_PIN_WIDGET_CONTROL_VREF_EN) HdaLog(" VREF"); if (Widgets[w].DefaultPinControl & HDA_PIN_WIDGET_CONTROL_IN_EN) HdaLog(" IN"); if (Widgets[w].DefaultPinControl & HDA_PIN_WIDGET_CONTROL_OUT_EN) HdaLog(" OUT"); if (Widgets[w].DefaultPinControl & HDA_PIN_WIDGET_CONTROL_HP_EN) HdaLog(" HP"); HdaLog("\n"); } // Print connections. if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_CONN_LIST) { HdaLog(" Connection: %u\n ", HDA_PARAMETER_CONN_LIST_LENGTH_LEN(Widgets[w].ConnectionListLength)); for (UINT8 c = 0; c < HDA_PARAMETER_CONN_LIST_LENGTH_LEN(Widgets[w].ConnectionListLength); c++) { HdaLog(" 0x%02X", Widgets[w].Connections[c]); //if (c == Widgets[w].ConnectionSelect) // HdaLog("*"); } HdaLog("\n"); } } } EFI_STATUS SaveHdaDumpTxt() { EFI_STATUS Status = EFI_NOT_FOUND; AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; HDA_CODEC_DEV *HdaCodecDev; EFI_HDA_CODEC_INFO_PROTOCOL *HdaCodecInfo; HDA_FUNC_GROUP *AudioFuncGroup; EFI_HDA_IO_PROTOCOL *HdaIo; CHAR16 *MiscPath = PoolPrint(L"%s\\misc", OEMPath); CHAR8 *MemLogStart; UINTN MemLogStartLen; // Print each codec found. for (UINTN i = 0; i < AudioNum; i++) { MemLogStartLen = GetMemLogLen(); MemLogStart = GetMemLogBuffer() + MemLogStartLen; HdaLog("HdaCodecDump Start\n"); Status = gBS->HandleProtocol(AudioList[i].Handle, &gEfiAudioIoProtocolGuid, (VOID**)&AudioIo); if (EFI_ERROR(Status)) continue; AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(AudioIo); if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo || !AudioIoPrivateData->HdaCodecDev->AudioFuncGroup) continue; HdaCodecDev = AudioIoPrivateData->HdaCodecDev; HdaCodecInfo = &HdaCodecDev->HdaCodecInfoData->HdaCodecInfo; AudioFuncGroup = HdaCodecDev->AudioFuncGroup; HdaIo = HdaCodecDev->HdaIo; // Get name. HdaLog("Codec: %s\n", HdaCodecDev->Name); // Get address UINT8 CodecAddress; Status = HdaIo->GetAddress(HdaIo, &CodecAddress); HdaLog("Address: %u\n", CodecAddress); // Get AFG ID. HdaLog("AFG Function Id: 0x%1X (unsol %u)\n", AudioFuncGroup->NodeId, AudioFuncGroup->UnsolCapable); HdaLog("Vendor ID: 0x%08X\n", HdaCodecDev->VendorId); HdaLog("Revision ID: 0x%08X\n", HdaCodecDev->RevisionId); // Get supported rates/formats. if ((AudioFuncGroup->SupportedPcmRates != 0) || (AudioFuncGroup->SupportedFormats != 0)) { HdaLog("Default PCM:\n"); HdaCodecDumpPrintRatesFormats(AudioFuncGroup->SupportedPcmRates, AudioFuncGroup->SupportedFormats); } else HdaLog("Default PCM: N/A\n"); // Get default amp caps. HdaLog("Default Amp-In caps: "); HdaCodecDumpPrintAmpCaps(AudioFuncGroup->AmpInCapabilities); HdaLog("Default Amp-Out caps: "); HdaCodecDumpPrintAmpCaps(AudioFuncGroup->AmpOutCapabilities); // Get widgets. HDA_WIDGET_DEV *Widgets = AudioFuncGroup->Widgets; UINTN WidgetCount = AudioFuncGroup->WidgetsCount; HdaCodecDumpPrintWidgets(HdaIo, Widgets, WidgetCount); CHAR16 *PathHdaDump = PoolPrint(L"%s\\HdaCodec#%d (%s).txt", MiscPath, i, HdaCodecDev->Name); if (PathHdaDump != NULL) { Status = egSaveFile(SelfRootDir, PathHdaDump, (VOID *)MemLogStart, GetMemLogLen() - MemLogStartLen); if (EFI_ERROR(Status)) Status = egSaveFile(NULL, PathHdaDump, (VOID *)MemLogStart, GetMemLogLen() - MemLogStartLen); FreePool(PathHdaDump); } } FreePool(MiscPath); return Status; } EFI_STATUS SaveHdaDumpBin() { EFI_STATUS Status = EFI_NOT_FOUND; AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; HDA_CODEC_DEV *HdaCodecDev; EFI_HDA_CODEC_INFO_PROTOCOL *HdaCodecInfo; HDA_FUNC_GROUP *AudioFuncGroup; EFI_HDA_IO_PROTOCOL *HdaIo; CHAR16 *MiscPath = PoolPrint(L"%s\\misc", OEMPath); if (MiscPath == NULL) return EFI_OUT_OF_RESOURCES; for (UINTN i = 0; i < AudioNum; i++) { HDA_WIDGET_DEV *Widgets; UINTN WidgetCount; UINT32 HdaCodecDataSize; HdaCodec HdaCodec; UINT8 CodecAddress; UINT8 *HdaCodecData; UINT8 *HdaCodecDataPtr; CHAR16 *PathHdaDump; Status = gBS->HandleProtocol(AudioList[i].Handle, &gEfiAudioIoProtocolGuid, (VOID**)&AudioIo); if (EFI_ERROR(Status)) continue; AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(AudioIo); if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) continue; HdaCodecDev = AudioIoPrivateData->HdaCodecDev; if(!HdaCodecDev || !HdaCodecDev->AudioFuncGroup) continue; HdaCodecInfo = &HdaCodecDev->HdaCodecInfoData->HdaCodecInfo; AudioFuncGroup = HdaCodecDev->AudioFuncGroup; HdaIo = HdaCodecDev->HdaIo; Widgets = AudioFuncGroup->Widgets; WidgetCount = AudioFuncGroup->WidgetsCount; HdaCodecDataSize = (UINT32)(sizeof(HdaCodec) + (WidgetCount * sizeof(HdaWidget))); // Copy codec data ZeroMem(&HdaCodec, sizeof(HdaCodec)); if(!EFI_ERROR(Status)) { for (UINT32 j = 0; j < HDA_MAX_NAMELEN; j++) { HdaCodec.Name[j] = (CHAR8)(HdaCodecDev->Name[j] & 0xFF); if (HdaCodecDev->Name[j] == 0x0000) break; } } Status = HdaIo->GetAddress(HdaIo, &CodecAddress); CopyMem(HdaCodec.Header, hdcID, 4); HdaCodec.CodecAddress = CodecAddress; HdaCodec.AudioFuncId = AudioFuncGroup->NodeId; HdaCodec.Unsol = AudioFuncGroup->UnsolCapable; HdaCodec.VendorId = HdaCodecDev->VendorId; HdaCodec.RevisionId = HdaCodecDev->RevisionId; HdaCodec.Rates = AudioFuncGroup->SupportedPcmRates; HdaCodec.Formats = AudioFuncGroup->SupportedFormats; HdaCodec.AmpInCaps = AudioFuncGroup->AmpInCapabilities; HdaCodec.AmpOutCaps = AudioFuncGroup->AmpOutCapabilities; HdaCodec.WidgetCount = AudioFuncGroup->WidgetsCount; // Allocate space for codec data HdaCodecData = AllocateZeroPool(HdaCodecDataSize); HdaCodecDataPtr = HdaCodecData; if (!HdaCodecData) continue; CopyMem(HdaCodecDataPtr, &HdaCodec, sizeof(HdaCodec)); HdaCodecDataPtr += sizeof(HdaCodec); for (UINT32 w = 0; w < WidgetCount; w++) { UINTN ConnectionListLength; HdaWidget HdaWidget; ConnectionListLength = HDA_PARAMETER_CONN_LIST_LENGTH_LEN(Widgets[w].ConnectionListLength); ZeroMem(&HdaWidget, sizeof(HdaWidget)); HdaWidget.NodeId = Widgets[w].NodeId; HdaWidget.Type = Widgets[w].Type; HdaWidget.Capabilities = Widgets[w].Capabilities; HdaWidget.DefaultUnSol = Widgets[w].DefaultUnSol; HdaWidget.ConnectionListLength = Widgets[w].ConnectionListLength; HdaWidget.ConnectionSelect = 0; HdaWidget.SupportedPowerStates = Widgets[w].SupportedPowerStates; HdaWidget.DefaultPowerState = Widgets[w].DefaultPowerState; HdaWidget.AmpOverride = Widgets[w].AmpOverride; HdaWidget.AmpInCapabilities = Widgets[w].AmpInCapabilities; HdaWidget.AmpOutCapabilities = Widgets[w].AmpOutCapabilities; HdaWidget.AmpOutLeftDefaultGainMute = Widgets[w].AmpOutLeftDefaultGainMute; HdaWidget.AmpOutRightDefaultGainMute = Widgets[w].AmpOutRightDefaultGainMute; HdaWidget.SupportedPcmRates = Widgets[w].SupportedPcmRates; HdaWidget.SupportedFormats = Widgets[w].SupportedFormats; HdaWidget.DefaultConvFormat = Widgets[w].DefaultConvFormat; HdaWidget.DefaultConvStreamChannel = Widgets[w].DefaultConvStreamChannel; HdaWidget.DefaultConvChannelCount = Widgets[w].DefaultConvChannelCount; HdaWidget.PinCapabilities = Widgets[w].PinCapabilities; HdaWidget.DefaultEapd = Widgets[w].DefaultEapd; HdaWidget.DefaultPinControl = Widgets[w].DefaultPinControl; HdaWidget.DefaultConfiguration = Widgets[w].DefaultConfiguration; HdaWidget.VolumeCapabilities = Widgets[w].VolumeCapabilities; HdaWidget.DefaultVolume = Widgets[w].DefaultVolume; for (UINT32 c = 0; c < ConnectionListLength; c++) { if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_IN_AMP) { HdaWidget.AmpInLeftDefaultGainMute[c] = Widgets[w].AmpInLeftDefaultGainMute[c]; if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_STEREO) { HdaWidget.AmpInRightDefaultGainMute[c] = Widgets[w].AmpInRightDefaultGainMute[c]; } } if (Widgets[w].Capabilities & HDA_PARAMETER_WIDGET_CAPS_CONN_LIST) { HdaWidget.Connections[c] = Widgets[w].Connections[c]; } } CopyMem(HdaCodecDataPtr, &HdaWidget, sizeof(HdaWidget)); HdaCodecDataPtr += sizeof(HdaWidget); } PathHdaDump = PoolPrint(L"%s\\HdaCodec#%d (%s).bin", MiscPath, i, HdaCodecDev->Name); if (PathHdaDump != NULL) { Status = egSaveFile(SelfRootDir, PathHdaDump, HdaCodecData, HdaCodecDataSize); if (EFI_ERROR(Status)) Status = egSaveFile(NULL, PathHdaDump, HdaCodecData, HdaCodecDataSize); FreePool(PathHdaDump); } FreePool(HdaCodecData); } FreePool(MiscPath); return EFI_SUCCESS; }