/* * File: HdaCodecAudioIo.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. */ #ifdef _WIN32 #pragma warning (disable: 4054) #endif //#include "HdaCodec.h" #include "../AudioDxe.h" //#include #include /* // HDA I/O Stream callback. VOID HdaCodecHdaIoStreamCallback( IN EFI_HDA_IO_PROTOCOL_TYPE Type, IN VOID *Context1, IN VOID *Context2, IN VOID *Context3) { // DEBUG((DEBUG_INFO, "HdaCodecHdaIoStreamCallback(): start\n")); // Create variables. EFI_AUDIO_IO_PROTOCOL *AudioIo = (EFI_AUDIO_IO_PROTOCOL*)Context1; EFI_AUDIO_IO_CALLBACK AudioIoCallback = (EFI_AUDIO_IO_CALLBACK)Context2; // Ensure required parameters are valid. if ((AudioIo == NULL) || (AudioIoCallback == NULL)) return; // Invoke callback. AudioIoCallback(AudioIo, Context3); } */ /** Gets the collection of output ports. @param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance. @param[out] OutputPorts A pointer to a buffer where the output ports will be placed. @param[out] OutputPortsCount The number of ports in OutputPorts. @retval EFI_SUCCESS The audio data was played successfully. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. **/ EFI_STATUS EFIAPI HdaCodecAudioIoGetOutputs( IN EFI_AUDIO_IO_PROTOCOL *This, OUT EFI_AUDIO_IO_PROTOCOL_PORT **OutputPorts, OUT UINTN *OutputPortsCount) { // DEBUG((DEBUG_INFO, "HdaCodecAudioIoGetOutputs(): start\n")); // Create variables. EFI_STATUS Status; AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; HDA_CODEC_DEV *HdaCodecDev; EFI_AUDIO_IO_PROTOCOL_PORT *HdaOutputPorts; UINT32 SupportedRates; UINTN i; // If a parameter is invalid, return error. if ((This == NULL) || (OutputPorts == NULL) || (OutputPortsCount == NULL)) return EFI_INVALID_PARAMETER; // Get private data. AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This); if (!AudioIoPrivateData) { return EFI_NOT_STARTED; } HdaCodecDev = AudioIoPrivateData->HdaCodecDev; // Allocate buffer. HdaOutputPorts = AllocateZeroPool(sizeof(EFI_AUDIO_IO_PROTOCOL_PORT) * HdaCodecDev->OutputPortsCount); if (HdaOutputPorts == NULL) return EFI_OUT_OF_RESOURCES; // Get output ports. for (i = 0; i < HdaCodecDev->OutputPortsCount; i++) { // Port is an output. HdaOutputPorts[i].Type = EfiAudioIoTypeOutput; // Get device type. switch (HDA_VERB_GET_CONFIGURATION_DEFAULT_DEVICE(HdaCodecDev->OutputPorts[i]->DefaultConfiguration)) { case HDA_CONFIG_DEFAULT_DEVICE_LINE_OUT: case HDA_CONFIG_DEFAULT_DEVICE_LINE_IN: HdaOutputPorts[i].Device = EfiAudioIoDeviceLine; break; case HDA_CONFIG_DEFAULT_DEVICE_SPEAKER: HdaOutputPorts[i].Device = EfiAudioIoDeviceSpeaker; break; case HDA_CONFIG_DEFAULT_DEVICE_HEADPHONE_OUT: HdaOutputPorts[i].Device = EfiAudioIoDeviceHeadphones; break; case HDA_CONFIG_DEFAULT_DEVICE_SPDIF_OUT: case HDA_CONFIG_DEFAULT_DEVICE_SPDIF_IN: HdaOutputPorts[i].Device = EfiAudioIoDeviceSpdif; break; case HDA_CONFIG_DEFAULT_DEVICE_MIC_IN: HdaOutputPorts[i].Device = EfiAudioIoDeviceMic; break; default: if (HdaCodecDev->OutputPorts[i]->PinCapabilities & HDA_PARAMETER_PIN_CAPS_HDMI) HdaOutputPorts[i].Device = EfiAudioIoDeviceHdmi; else HdaOutputPorts[i].Device = EfiAudioIoDeviceOther; } // Get location. switch (HDA_VERB_GET_CONFIGURATION_DEFAULT_LOC(HdaCodecDev->OutputPorts[i]->DefaultConfiguration)) { case HDA_CONFIG_DEFAULT_LOC_SPEC_NA: HdaOutputPorts[i].Location = EfiAudioIoLocationNone; break; case HDA_CONFIG_DEFAULT_LOC_SPEC_REAR: HdaOutputPorts[i].Location = EfiAudioIoLocationRear; break; case HDA_CONFIG_DEFAULT_LOC_SPEC_FRONT: HdaOutputPorts[i].Location = EfiAudioIoLocationFront; break; case HDA_CONFIG_DEFAULT_LOC_SPEC_LEFT: HdaOutputPorts[i].Location = EfiAudioIoLocationLeft; break; case HDA_CONFIG_DEFAULT_LOC_SPEC_RIGHT: HdaOutputPorts[i].Location = EfiAudioIoLocationRight; break; case HDA_CONFIG_DEFAULT_LOC_SPEC_TOP: HdaOutputPorts[i].Location = EfiAudioIoLocationTop; break; case HDA_CONFIG_DEFAULT_LOC_SPEC_BOTTOM: HdaOutputPorts[i].Location = EfiAudioIoLocationBottom; break; default: HdaOutputPorts[i].Location = EfiAudioIoLocationOther; } // Get surface. switch (HDA_VERB_GET_CONFIGURATION_DEFAULT_SURF(HdaCodecDev->OutputPorts[i]->DefaultConfiguration)) { case HDA_CONFIG_DEFAULT_LOC_SURF_EXTERNAL: HdaOutputPorts[i].Surface = EfiAudioIoSurfaceExternal; break; case HDA_CONFIG_DEFAULT_LOC_SURF_INTERNAL: HdaOutputPorts[i].Surface = EfiAudioIoSurfaceInternal; break; default: HdaOutputPorts[i].Surface = EfiAudioIoSurfaceOther; } // Get supported stream formats. Status = HdaCodecGetSupportedPcmRates(HdaCodecDev->OutputPorts[i], &SupportedRates); if (EFI_ERROR(Status)) return Status; // Get supported bit depths. HdaOutputPorts[i].SupportedBits = 0; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8BIT) HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits8; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16BIT) HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits16; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_20BIT) HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits20; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_24BIT) HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits24; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32BIT) HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits32; // Get supported sample rates. HdaOutputPorts[i].SupportedFreqs = 0; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq8kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_11KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq11kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq16kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_22KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq22kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq32kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_44KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq44kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_48KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq48kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_88KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq88kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_96KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq96kHz; if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_192KHZ) HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq192kHz; } // Ports gotten successfully. *OutputPorts = HdaOutputPorts; *OutputPortsCount = HdaCodecDev->OutputPortsCount; return EFI_SUCCESS; } /** Sets up the device to play audio data. @param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance. @param[in] OutputIndex The zero-based index of the desired output. @param[in] Volume The volume (0-100) to use. @param[in] Bits The width in bits of the source data. @param[in] Freq The frequency of the source data. @param[in] Channels The number of channels the source data contains. @retval EFI_SUCCESS The audio data was played successfully. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. **/ EFI_STATUS EFIAPI HdaCodecAudioIoSetupPlayback( IN EFI_AUDIO_IO_PROTOCOL *This, IN UINT8 OutputIndex, IN UINT8 Volume, IN EFI_AUDIO_IO_PROTOCOL_FREQ Freq, IN EFI_AUDIO_IO_PROTOCOL_BITS Bits, IN UINT8 Channels) { // DEBUG((DEBUG_INFO, "HdaCodecAudioIoSetupPlayback(): start\n")); // Create variables. EFI_STATUS Status; AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; HDA_CODEC_DEV *HdaCodecDev; EFI_HDA_IO_PROTOCOL *HdaIo; // Widgets. HDA_WIDGET_DEV *PinWidget; HDA_WIDGET_DEV *OutputWidget; UINT32 SupportedRates; UINT8 HdaStreamId; // Stream. UINT8 StreamBits, StreamDiv, StreamMult = 0; BOOLEAN StreamBase44kHz = FALSE; UINT16 StreamFmt; // If a parameter is invalid, return error. if ((This == NULL) || (Volume > EFI_AUDIO_IO_PROTOCOL_MAX_VOLUME)) return EFI_INVALID_PARAMETER; // Get private data. AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This); HdaCodecDev = AudioIoPrivateData->HdaCodecDev; HdaIo = HdaCodecDev->HdaIo; // Check that output index is within bounds and get our desired output. if (OutputIndex >= HdaCodecDev->OutputPortsCount) return EFI_INVALID_PARAMETER; PinWidget = HdaCodecDev->OutputPorts[OutputIndex]; // Get the output DAC for the path. Status = HdaCodecGetOutputDac(PinWidget, &OutputWidget); if (EFI_ERROR(Status)) return Status; // Get supported stream formats. Status = HdaCodecGetSupportedPcmRates(OutputWidget, &SupportedRates); if (EFI_ERROR(Status)) return Status; // Determine bitness of samples, ensuring desired bitness is supported. switch (Bits) { // 8-bit. case EfiAudioIoBits8: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8BIT)) return EFI_UNSUPPORTED; StreamBits = HDA_CONVERTER_FORMAT_BITS_8; break; // 16-bit. case EfiAudioIoBits16: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16BIT)) return EFI_UNSUPPORTED; StreamBits = HDA_CONVERTER_FORMAT_BITS_16; break; // 20-bit. case EfiAudioIoBits20: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_20BIT)) return EFI_UNSUPPORTED; StreamBits = HDA_CONVERTER_FORMAT_BITS_20; break; // 24-bit. case EfiAudioIoBits24: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_24BIT)) return EFI_UNSUPPORTED; StreamBits = HDA_CONVERTER_FORMAT_BITS_24; break; // 32-bit. case EfiAudioIoBits32: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32BIT)) return EFI_UNSUPPORTED; StreamBits = HDA_CONVERTER_FORMAT_BITS_32; break; // Others. default: return EFI_INVALID_PARAMETER; } // Determine base, divisor, and multipler. switch (Freq) { // 8 kHz. case EfiAudioIoFreq8kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = FALSE; StreamDiv = 6; StreamMult = 1; break; // 11.025 kHz. case EfiAudioIoFreq11kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_11KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = TRUE; StreamDiv = 4; StreamMult = 1; break; // 16 kHz. case EfiAudioIoFreq16kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = FALSE; StreamDiv = 3; StreamMult = 1; break; // 22.05 kHz. case EfiAudioIoFreq22kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_22KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = TRUE; StreamDiv = 2; StreamMult = 1; break; // 32 kHz. case EfiAudioIoFreq32kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = FALSE; StreamDiv = 3; StreamMult = 2; break; // 44.1 kHz. case EfiAudioIoFreq44kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_44KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = TRUE; StreamDiv = 1; StreamMult = 1; break; // 48 kHz. case EfiAudioIoFreq48kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_48KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = FALSE; StreamDiv = 1; StreamMult = 1; break; // 88 kHz. case EfiAudioIoFreq88kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_88KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = TRUE; StreamDiv = 1; StreamMult = 2; break; // 96 kHz. case EfiAudioIoFreq96kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_96KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = FALSE; StreamDiv = 1; StreamMult = 2; break; // 192 kHz. case EfiAudioIoFreq192kHz: if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_192KHZ)) return EFI_UNSUPPORTED; StreamBase44kHz = FALSE; StreamDiv = 1; StreamMult = 4; break; // Others. default: return EFI_INVALID_PARAMETER; } // Disable all widget paths. for (UINTN w = 0; w < HdaCodecDev->OutputPortsCount; w++) { if (w == OutputIndex) continue; Status = HdaCodecDisableWidgetPath(HdaCodecDev->OutputPorts[w]); if (EFI_ERROR(Status)) return Status; } // Close stream first. Status = HdaIo->CloseStream(HdaIo, EfiHdaIoTypeOutput); if (EFI_ERROR(Status)) return Status; // Calculate stream format and setup stream. StreamFmt = HDA_CONVERTER_FORMAT_SET(Channels - 1, StreamBits, StreamDiv - 1, StreamMult - 1, StreamBase44kHz); DEBUG((DEBUG_INFO, "HdaCodecAudioIoPlay(): Stream format 0x%X\n", StreamFmt)); Status = HdaIo->SetupStream(HdaIo, EfiHdaIoTypeOutput, StreamFmt, &HdaStreamId); if (EFI_ERROR(Status)) return Status; // Setup widget path for desired output. AudioIoPrivateData->SelectedOutputIndex = OutputIndex; Status = HdaCodecEnableWidgetPath(PinWidget, Volume, HdaStreamId, StreamFmt); if (EFI_ERROR(Status)) goto CLOSE_STREAM; return EFI_SUCCESS; CLOSE_STREAM: // Close stream. HdaIo->CloseStream(HdaIo, EfiHdaIoTypeOutput); return Status; } /** Begins playback on the device and waits for playback to complete. @param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance. @param[in] Data A pointer to the buffer containing the audio data to play. @param[in] DataLength The size, in bytes, of the data buffer specified by Data. @param[in] Position The position in the buffer to start at. @retval EFI_SUCCESS The audio data was played successfully. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. **/ EFI_STATUS EFIAPI HdaCodecAudioIoStartPlayback( IN EFI_AUDIO_IO_PROTOCOL *This, IN VOID *Data, IN UINTN DataLength, IN UINTN Position OPTIONAL) { // DEBUG((DEBUG_INFO, "HdaCodecAudioIoStartPlayback(): start\n")); // Create variables. EFI_STATUS Status; AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; EFI_HDA_IO_PROTOCOL *HdaIo; BOOLEAN StreamRunning = FALSE; // If a parameter is invalid, return error. if ((This == NULL) || (Data == NULL) || (DataLength == 0)) return EFI_INVALID_PARAMETER; // Get private data. AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This); if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) { return EFI_NOT_FOUND; } HdaIo = AudioIoPrivateData->HdaCodecDev->HdaIo; // Start stream. Status = HdaIo->StartStream(HdaIo, EfiHdaIoTypeOutput, Data, DataLength, Position, NULL, NULL, NULL, NULL); if (EFI_ERROR(Status)) return Status; // Wait for stream to stop. StreamRunning = TRUE; while (StreamRunning) { Status = HdaIo->GetStream(HdaIo, EfiHdaIoTypeOutput, &StreamRunning); if (EFI_ERROR(Status)) { HdaIo->StopStream(HdaIo, EfiHdaIoTypeOutput); return Status; } // Wait 100ms. gBS->Stall(MS_TO_MICROSECOND(100)); } return EFI_SUCCESS; } /** Begins playback on the device asynchronously. @param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance. @param[in] Data A pointer to the buffer containing the audio data to play. @param[in] DataLength The size, in bytes, of the data buffer specified by Data. @param[in] Position The position in the buffer to start at. @param[in] Callback A pointer to an optional callback to be invoked when playback is complete. @param[in] Context A pointer to data to be passed to the callback function. @retval EFI_SUCCESS The audio data was played successfully. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. **/ EFI_STATUS EFIAPI HdaCodecAudioIoStartPlaybackAsync( IN EFI_AUDIO_IO_PROTOCOL *This, IN VOID *Data, IN UINTN DataLength, IN UINTN Position OPTIONAL, IN EFI_AUDIO_IO_CALLBACK Callback OPTIONAL, IN VOID *Context OPTIONAL) { // DEBUG((DEBUG_INFO, "HdaCodecAudioIoStartPlaybackAsync(): start\n")); // Create variables. EFI_STATUS Status; AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; EFI_HDA_IO_PROTOCOL *HdaIo; // If a parameter is invalid, return error. if ((This == NULL) || (Data == NULL) || (DataLength == 0)) return EFI_INVALID_PARAMETER; // Get private data. AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This); if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) { return EFI_NOT_FOUND; } HdaIo = AudioIoPrivateData->HdaCodecDev->HdaIo; // Start stream. // Status = HdaIo->StartStream(HdaIo, EfiHdaIoTypeOutput, Data, DataLength, Position, // (VOID*)HdaCodecHdaIoStreamCallback, (VOID*)This, (VOID*)Callback, Context); Status = HdaIo->StartStream(HdaIo, EfiHdaIoTypeOutput, Data, DataLength, Position, NULL, (VOID*)This, NULL, Context); return Status; } /** Stops playback on the device. @param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance. @retval EFI_SUCCESS The audio data was played successfully. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. **/ EFI_STATUS EFIAPI HdaCodecAudioIoStopPlayback( IN EFI_AUDIO_IO_PROTOCOL *This) { DEBUG((DEBUG_INFO, "HdaCodecAudioIoStopPlayback(): start\n")); // Create variables. AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData; EFI_HDA_IO_PROTOCOL *HdaIo; // If a parameter is invalid, return error. if (This == NULL) return EFI_INVALID_PARAMETER; // Get private data. AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This); if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) { return EFI_NOT_FOUND; } HdaIo = AudioIoPrivateData->HdaCodecDev->HdaIo; // Stop stream. return HdaIo->StopStream(HdaIo, EfiHdaIoTypeOutput); }